我应该在App.xaml中声明转换器还是作为每个文件的资源?

17

在WPF应用程序中声明转换器时,我应该:

  1. 所有的转换器声明在App.xaml中(即在<Application.Resources/>中),以便整个应用程序都可以使用它。
  2. 仅在每个Page/Window/ResourceDictionary/UserControl等的Resources部分中声明所需的转换器。
  3. 完全使用其他方法

关于可读性,我认为方法1是最好的,但我的问题是关于性能的。哪种方法在性能、内存等方面最有效率?

4个回答

56

那么,我根本不在xaml中声明它们。相反,我另外从MarkupExtension派生我的一个转换器。像这样:

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) { }
}

这使我可以在任何地方使用我的转换器,例如:

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

converters是我声明转换器的命名空间。

这个技巧是从一个旧的stackoverflow线程中学习来的。


2
是的,从性能方面来看,这种方法更好,因为它不会在每次使用转换器时实例化一个新对象。它只在第一次调用MarkupExtension之前创建一个实例,并在每次调用时返回相同的实例。 - Yogesh
谢谢!这让生活更简单了。 - si618
1
你为什么要创建另一个值转换器的实例来返回 _MarkupExtension_? - Dave
1
值转换器只会被创建一次。 - Yogesh
嗯,在应用程序级别查找转换器的查找时间可能比在窗口级别实例化一个转换器的时间更长,但是所花费的时间微不足道。然而,我经常在我的转换器上拥有属性,以定制它们在给定上下文中的使用方式,因此我更喜欢后者。 - markmnl
一个小问题,出于某种原因,像这样做不会在设计器转换器选择器中显示。 - Luk164

2
我有一个ResourceDictionary,其中声明了几个常用的转换器,例如bool-to-visibility转换器。我直接在App.xaml中引用这个字典。
我在页面/窗口级别(或由页面/窗口引用的ResourceDictionary中)声明其他更具体的转换器。
我无法确定性能问题的答案,但如果它在加载时间或内存使用方面产生实际差异,我会非常惊讶。声明转换器基本上是对象实例化,因此应该非常高效且使用非常少的内存,但我没有进行任何分析以比较应用程序级别和窗口级别的性能。

那就是我的问题... 如果您以后知道了性能的答案,请不要忘记回来告诉我。 - Shimmy Weitzhandler

0

如果您只需要一个窗口的转换器,我会将其放在该窗口上(甚至仅放在容器控件上,该控件包含使用它的控件)。

我认为这样更易于维护 - 您可以查看转换器声明并能够知道谁在使用它。您知道,如果您更改了特定页面上的控件以不再使用转换器,则可以从页面资源中删除它而不影响其他任何内容。相反,如果转换器是应用程序资源,则不那么容易确定是否有任何东西在使用它。

如果同一转换器被多个页面使用,我仍然会将其放在每个页面资源下面。实际上,在XAML中只需要额外添加一行。

无论如何,这是我今天的观点。我期待着另一篇文章提出完全相反的观点。 :-)


没这么幸运,我的答案一半相反,一半相同 :-P - devuxer

0
@Yogesh的答案太棒了。为了完整起见,我创建了一个基类来减少代码量:
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()];
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接