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.?

Sean Hanley
  • 5,677
  • 7
  • 42
  • 53
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632

4 Answers4

56

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.

Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
Yogesh
  • 14,498
  • 6
  • 44
  • 69
  • 2
    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. – Yogesh Nov 03 '09 at 03:32
  • Thanks! This makes life easier. – si618 Sep 25 '10 at 03:50
  • 1
    Why do you create another Instance of the value converter to return for the _MarkupExtension_? – Dave May 06 '11 at 18:42
  • 1
    The value converter is only created once. – Yogesh May 12 '12 at 20:32
  • 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. – markmnl Jun 27 '12 at 03:38
  • One nitpick, for some reason doing it like this does not show up in the designer convertor selector. – Luk164 Jan 03 '21 at 14:20
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.

devuxer
  • 41,681
  • 47
  • 180
  • 292
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. :-)

Andrew Shepherd
  • 44,254
  • 30
  • 139
  • 205
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()];
    }
}
Dominic Jonas
  • 4,717
  • 1
  • 34
  • 77