2011-03-02 49 views

回答

16

您需要在转换器资源指定x:Shared="False"。这里是一个例子:

<BooleanToVisibilityConverter x:Key="MyConverter" x:Shared="False"/> 
+0

帕夫洛取代普通转换器你是男人! – NVM 2011-03-02 11:31:57

2

您可以在每个控制单独的资源:

<TextBox> 
     <TextBox.Resources> 
      <Converters:VisibilityConverter x:Key="conv"/> 
     </TextBox.Resources> 
     <TextBox.Text> 
      <Binding Converter="{StaticResource conv}"/> 
     </TextBox.Text> 
    </TextBox> 
1

为什么?它应该是确定性的,并且不知道除了通过参数传递给它的任何状态。我已经使用了值转换器来保存图像的静态列表(将值转换为图像),并且工作正常 - 即使在具有数千行的数据网格的多个列中使用相同的转换器时也是如此。 (请注意,转换器仍不知道任何外部状态)。

在任何情况下,看是否能回答你的问题:Are value converters instantiated per-binding in WPF?

+2

我需要一个转换器来绑定两个可观察的集合或稍微不同的类型。我跟踪转换器中收集已更改的事件。因此每个实例。 – NVM 2011-03-02 11:31:27

0

如果你把你的转换器转化为资源,并通过{StaticResource ConverterName}查找引用它们,那么他们每个实例化资源字典的情况只有一次。

但是更好的方法是从MarkupExtension继承您的转换器,并直接使用它们,而不是将它们添加到资源并引用它们。

下面是这样一个基类的一个实例:

http://www.snippetsource.net/Snippet/18/base-class-for-valueconverters-in-wpf

问候 基督教

+0

链接已死,请更新,如果它仍然存在 – Maslow 2017-02-16 13:36:22

0

MarkupExtension继承,然后创建在构造函数中的转换器。

public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     _converter = new FlagsToBoolConverter(); 
     return _converter; 
    } 

下面是一个完整的例子。它是一个需要实例化的标志转换器,以保留ConvertBack的源值。

using System; 
using System.Globalization; 
using System.Runtime.CompilerServices; 
using System.Windows; 
using System.Windows.Data; 
using System.Windows.Markup; 

namespace Something 
{ 
    public class FlagsToBoolConverter : MarkupExtension, IValueConverter 
    { 
     private FlagsToBoolConverter _converter; 

     public override object ProvideValue(IServiceProvider serviceProvider) 
     { 
      _converter = new FlagsToBoolConverter(); 
      return _converter; 
     } 

     private ulong _sourceValue; 

     public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      try 
      { 
       var type = value.GetType(); 
       if (type.IsEnum) 
       { 
        ulong mask = (ulong)System.Convert.ChangeType(Enum.Parse(type, (string)parameter), typeof(ulong)); 
        _sourceValue = (ulong)System.Convert.ChangeType(Enum.Parse(type, value.ToString()), typeof(ulong)); 
        return ((mask & _sourceValue) != 0); 
       } 
       return value; 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("FlagsEnumValueConverter: Invalid Cast(to) Value={0} Type={1} Param={2} Exception{3}", value, targetType, parameter, ex); 
      } 
      return value; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      try 
      { 
       if (targetType.IsEnum) 
       { 
        var original = this._sourceValue; 
        var originalEnum = Enum.Parse(targetType, original.ToString()); 
        var maskEnum = Enum.Parse(targetType, (string)parameter); 
        var mask = (ulong)System.Convert.ChangeType(maskEnum, typeof(ulong)); 
        _sourceValue ^= mask; 
        var sourceEnum = Enum.Parse(targetType, _sourceValue.ToString()); 
        Console.WriteLine($"Modified Value: {original} ({originalEnum}) by Mask {mask} ({maskEnum}) Result = {_sourceValue} ({sourceEnum})"); 
        return sourceEnum; 
       } 
       return value; 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("FlagsEnumValueConverter: Invalid Cast(from) Value={0} Type={1} Param={2} Exception{3}", value, targetType, parameter, ex); 
      } 
      return value; 
     } 
    } 
} 

您的前缀需要声明为xmlns:src="clr-namespace:Something"。然后在你的绑定与Converter={src:FlagsToBoolConverter}

<CheckBox IsChecked="{Binding SomeFlagsEnum, ConverterParameter=FlagA, Converter={src:FlagsToBoolConverter}}">FlagA</CheckBox> 
    <CheckBox IsChecked="{Binding SomeFlagsEnum, ConverterParameter=FlagB, Converter={src:FlagsToBoolConverter}}">FlagB</CheckBox> 
    <CheckBox IsChecked="{Binding SomeFlagsEnum, ConverterParameter=FlagC, Converter={src:FlagsToBoolConverter}}">FlagC</CheckBox>