Should I declare converters in App.xaml or as a per-file resource?
Asked Answered
M

4

17

When declaring converters in a WPF application, should I:

  1. Declare all my converters in the App.xaml (i.e. in <Application.Resources/>) so it's available to the entire application
  2. Declare only needed converters for each Page/Window/ResourceDictionary/UserControl etc. in their Resources section
  3. Something else entirely

Regarding readability, method 1 seems the best to me, but my question is about performance. Which method is the most resource efficient in terms of performance, memory, etc.?

Melly answered 2/11, 2009 at 3:17 Comment(0)
R
57

Well, I just don't declare them in xaml at all. Instead, I additionally derive a converter of mine from MarkupExtension. Like this:

public class MyValueConverter : MarkupExtension, IValueConverter
{
    private static MyValueConverter _converter = null;
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (_converter == null) _converter = new MyValueConverter();    
        return _converter;
    }

    public object Convert
     (object value, Type targetType, object parameter, CultureInfo culture) { }
    public object ConvertBack
     (object value, Type targetType, object parameter, CultureInfo culture) { }
}

This allows me to use my converter anywhere, like this:

Source="{Binding myValue, Converter={converters:MyValueConverter}}"

where converters is the namespace in which I have declared my converter.

Learned this trick from an old stackoverflow thread only.

Rausch answered 2/11, 2009 at 9:54 Comment(5)
And yes, this is better in terms of performance as it does not instantiate a new object every time the converter is used. It only creates one instance before the return of the first call to the MarkupExtension and returns the same instance every time.Rausch
Why do you create another Instance of the value converter to return for the MarkupExtension?Uriniferous
The value converter is only created once.Rausch
hmm the lookup time to find a converter at the application level will probably take longer than the instantiation of one at the Window level, anyway the time take is negligible. however I often have properties on my converters to customize there usage in a given context so I prefer the latter.Hundred
One nitpick, for some reason doing it like this does not show up in the designer convertor selector.Kevinkevina
G
2

I have a ResourceDictionary that declares several commonly needed converters, such as a bool-to-visibility converter. I reference this dictionary directly in App.xaml.

I declare other converters that are more specific to a given situation at the Page/Window-level (or in a ResourceDictionary referenced by a Page/Window).

I can't answer the performance question definitively, but I would be very surprised if it made a practical difference in load time or memory usage. Declaring a converter is basically an object instantiation, so it should be very efficient and use very little memory, but I haven't done any profiling to compare app-level vs. window-level performance.

Gregarious answered 2/11, 2009 at 6:10 Comment(1)
Well that was my question... If you will ever know the performance answer, please don't forget to come back.Melly
P
0

If you only need a converter for the one window, I would put it for the one window (or even for just the container control that holds the control that uses it).

I would argue that this is more maintainable - you can look at the converter declaration and be able to tell what uses it. You know that if you change the controls on that particular page to no longer use the converter, you can take it out of the page's resources without affecting anything else. Conversely, if a converter is an application resource, it's not so simple to ascertain what's using it, if anything.

If the same converter is being used by more than one page, I would still put it under each page resource. Really, it's only one extra line in the XAML.

Anyway, that's my opinion, as of today. I'm expecting another post arguing exactly the opposite. :-)

Pham answered 2/11, 2009 at 4:53 Comment(1)
No such luck. My answer was half opposite, half the same :-PGregarious
S
0

@Yogesh answer is awesome. Just for completeness I created a base class for less code:

public abstract class ConverterMarkupExtension : MarkupExtension
{
    private static readonly Dictionary<Type, IValueConverter> Converters = new();

    protected ConverterMarkupExtension()
    {
        if (!typeof(IValueConverter).IsAssignableFrom(GetType()))
            throw new Exception($"{nameof(ConverterMarkupExtension)} can only be used with {nameof(IValueConverter)}");
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if(!Converters.ContainsKey(GetType()))
            Converters.Add(GetType(), (IValueConverter)Activator.CreateInstance(GetType())!);
        return Converters[GetType()];
    }
}
Sambo answered 28/6, 2023 at 11:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.