C# 带MarkupExtension的IValueConverter

C# 带MarkupExtension的IValueConverter,c#,wpf,converter,ivalueconverter,markup-extensions,C#,Wpf,Converter,Ivalueconverter,Markup Extensions,最近我读到一个IValueConverter,它也继承了MarkupExtension。有点像: internal class BoolToVisibilityConverter : MarkupExtension, IValueConverter { private static BoolToVisibilityConverter converter; public BoolToVisibilityConverter() { } public objec

最近我读到一个
IValueConverter
,它也继承了
MarkupExtension
。有点像:

internal class BoolToVisibilityConverter : MarkupExtension, IValueConverter
{
    private static BoolToVisibilityConverter converter;
    public BoolToVisibilityConverter()
    {
    }
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool)
        {
            if ((bool)value)
            {
                return Visibility.Visible;
            }
        }
        return Visibility.Collapsed;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is Visibility)
        {
            Visibility visibility = (Visibility)value;
            if (visibility == Visibility.Collapsed)
            {
                return false;
            }
        }
        return true;
    }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return converter ?? (converter = new BoolToVisibilityConverter());
    }
}
用法如下所示:

<Button Content="Delete" Visibility="{Binding CanDelete, UpdateSourceTrigger=PropertyChanged, Converter={local:BoolToVisibilityConverter}"/>
internal class BoolToVisibilityConverter : MarkupExtension, IValueConverter
{
    public BoolToVisibilityConverter()
    {
    }
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool)
        {
            if ((bool)value)
            {
                return Visibility.Visible;
            }
        }
        return Visibility.Collapsed;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is Visibility)
        {
            Visibility visibility = (Visibility)value;
            if (visibility == Visibility.Collapsed)
            {
                return false;
            }
        }
        return true;
    }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;        
    }
}
如果我理解正确,第一个解决方案只创建此转换器的一个实例。第二个为每个XAML创建一个新的转换器实例,对吗?

在本例中,标记扩展提供的唯一(轻微)优势是更简洁的XAML语法

与此相反:

<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
...
{Binding SomeBooleanProperty, Converter={StaticResource BooleanToVisibilityConverter}}
在我看来,这真的不值得。如果您为保存击键而烦恼,您可以缩短用于引用转换器的键:

<BooleanToVisibilityConverter x:Key="btvc" />
...
{Binding SomeBooleanProperty, Converter={StaticResource my:btvc}}

...
{Binding SomeBooleanProperty,Converter={StaticResource my:btvc}


由于标记扩展的
ProvideValue
方法是一个实例方法,因此只能在创建类的实例后调用它。由于该类既是标记扩展又是转换器,因此每次代码的两个变体都将创建一个转换器。唯一的区别是第一个变量总是返回相同的转换器:但是它不会,停止创建另一个转换器。

使用
MarkupExtension
的一个巨大优势是它可以允许您将值传递给转换器,这些值可以用作参数或返回值,例如:

public class CustomNullToVisibilityConverter : MarkupExtension, IValueConverter
{
    public object NullValue { get; set; }
    public object NotNullValue { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) return NullValue;

        return NotNullValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
用法:

...
Visibility="{Binding Property, 
            Converter={cnv:CustomNullToVisibilityConverter 
                       NotNullValue=Visible, NullValue=Collapsed}}" />
...
确保在
.xaml
中引用转换器的名称空间


编辑:

我忘记提到的一件事是,你是正确的,这个方法每次使用时都会创建一个新的转换器实例,这是一个缺点

但是,没有什么可以阻止您将带有
MarkupExtension
的转换器添加到资源字典中-这样它将只实例化一次。像这样:

<cnv:CustomNullToVisibilityConverter x:Key="NullToVisibilityConverter"
        NotNullValue=Visible, NullValue=Collapsed />
...
Visibility="{Binding Property, Converter={StaticResource NullToVisibilityConverter}" />
...

...
可见性=“{Binding Property,Converter={StaticResource NullToVisibilityConverter}”/>
...
...
Visibility="{Binding Property, 
            Converter={cnv:CustomNullToVisibilityConverter 
                       NotNullValue=Visible, NullValue=Collapsed}}" />
...
<cnv:CustomNullToVisibilityConverter x:Key="NullToVisibilityConverter"
        NotNullValue=Visible, NullValue=Collapsed />
...
Visibility="{Binding Property, Converter={StaticResource NullToVisibilityConverter}" />
...