Avalonia
Avalonia copied to clipboard
Application resources confusion
I am facing the problem of getting application resources. Described it in discussions: https://github.com/AvaloniaUI/Avalonia/discussions/6019
As a result, it turned out that the indexer only returns inner elements: https://github.com/AvaloniaUI/Avalonia/blob/7842883961d094e08e9def7f30cf32fd573179c7/src/Avalonia.Base/Collections/AvaloniaDictionary.cs#L72
Instead of viewing all dictionaries as implemented in the "TryGetResource" methods https://github.com/AvaloniaUI/Avalonia/blob/7842883961d094e08e9def7f30cf32fd573179c7/src/Avalonia.Styling/Controls/ResourceDictionary.cs#L104
This needs to be fixed to avoid questions and difficulties when using
Doesn't sounds like a bug for me. Isn't WPF/UWP has the same behavior? Resources is a dictionary instance per control, and to lookup parent control it has separated method.
In WPF, there is no such problem and the work with application resources is direct.
Application.Current.Resources["ColorConnector"]
Doesn't the same code work in Avalonia?
No, this is exactly what I described in the discussion https://github.com/AvaloniaUI/Avalonia/discussions/6019
Any updates?
@StarlkYT current behavior is pretty much by design. Resources property is a dictionary, where indexer works as it would be expected from dictionary. It's possible to change it to match WPF behavior though. @grokys do you remember why current behavior differs from WPF?
I think I had some issues with DynamicResources in WPF which I don't see in Avalonia. I don't know if that's due to what you described in your issue or not. Nevertheless, I think it's not a big deal to use TryGetResource once you know it?! Is it for you a big deal?
It can be confusing. Because indexer gets resource from the dictionary. TryGetResource lookups in the merged dictionaries too. And TryFindResource lookups from the control ancestors' resources.
That's true, but on the other hand it may result in better performance if you know where to look into. Probably the naming should reflect that somehow.
I just ran across this one and agree this needs to be changed to follow WPF. Note that UWP and WinUI also search all dictionaries -- even merged ones -- when using the indexer.
What's even worse, there seems to be no one-liner way of getting resources in Avalonia now.
WPF/WinUI allowed:
fillColor = (Color)Application.Current.Resources["NeutralValueBackgroundColor"];
Avalonia requires:
Application.Current.Resources.TryGetResource("NeutralValueBackgroundColor", out object resource1);
fillColor = (Color)resource1;
Which is an extra throw-away variable.
I realize this was done for safety to some degree but the indexer will still throw exceptions if a value isn't found so forcing TryGetResource doesn't even help in all cases.
I would normally expect a generic method here that will return the expected type or default(T). Better to just allow the WPF functionality though.
Something like this is a lot more helpful
/// <summary>
/// Gets the first resource matching the given key within the application resources dictionary.
/// </summary>
/// <typeparam name="T">The type of resource to return.</typeparam>
/// <param name="app">The application instance.</param>
/// <param name="key">The resource key.</param>
/// <returns>The located resource or default(T).</returns>
public static T GetResource<T>(
this Application app,
object key)
{
if (Application.Current.Resources.TryGetResource(key, out object resource))
{
if (resource is T)
{
return (T)resource;
}
}
return default(T);
}
@maxkatz6 @grokys I propose this issue be resolved for 11.0 as it may be a breaking change. Either:
- Close it as "by design" accepting the difference from WPF and the work-around discussed above
- Make resource lookup with
Application.Current.Resources["ColorConnector"]
work in all cases that WPF works (would be best IMO).