如何确保为每个使用它的绑定创建一个新的值转换器实例?
答案 0 :(得分:16)
您需要在转换器资源上指定x:Shared="False"
。这是一个例子:
<BooleanToVisibilityConverter x:Key="MyConverter" x:Shared="False"/>
答案 1 :(得分:3)
您可以在每个控件中创建单独的资源:
<TextBox>
<TextBox.Resources>
<Converters:VisibilityConverter x:Key="conv"/>
</TextBox.Resources>
<TextBox.Text>
<Binding Converter="{StaticResource conv}"/>
</TextBox.Text>
</TextBox>
答案 2 :(得分:1)
为什么呢?它应该是确定性的,并且不知道任何状态,除了通过其参数传递给它的状态。我使用值转换器来保留静态图像列表(一个值转换为图像),这很好 - 即使在具有数千行的数据网格中的多个列上使用相同的转换器时也是如此。 (注意转换器仍然没有意识到任何外部状态。)
无论如何,请查看这是否回答了您的问题:Are value converters instantiated per-binding in WPF?
答案 3 :(得分: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>
答案 4 :(得分:-1)
如果您将转换器放入资源并通过{StaticResource ConverterName}
查找引用它们,那么它们只会在每个资源字典实例中实例化一次。
但更好的方法是从MarkupExtension
继承转换器并直接使用它们,而不是将它们添加到资源中并引用它们。
以下是此类基类的示例:
http://www.snippetsource.net/Snippet/18/base-class-for-valueconverters-in-wpf
问候 基督教