具有MarkupExtension的IValueConverter

Tom*_*tom 6 c# wpf converter markup-extensions ivalueconverter

最近我读到了一个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());
    }
}
Run Code Online (Sandbox Code Playgroud)

用法看起来像:

<Button Content="Delete" Visibility="{Binding CanDelete, UpdateSourceTrigger=PropertyChanged, Converter={local:BoolToVisibilityConverter}"/>
Run Code Online (Sandbox Code Playgroud)

我习惯使用资源转换器,如:

<loc:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
...
<Button Content="Delete" Visibility="{Binding CanDelete, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BoolToVisibilityConverter}"/>
Run Code Online (Sandbox Code Playgroud)

我现在的第一个问题是:更好的方法是什么?如果我使用MarkupExtension-Version(除了使用更容易键入),它有什么优势?

我还看到了一个非常类似的实现,看起来像:

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;        
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我理解正确,第一个解决方案只创建一个这个转换器的实例.第二个为每个XAML创建一个这个转换器的新实例,对吧?

Ste*_*nds 8

在这种情况下,标记扩展提供的唯一(轻微)优势是更简洁的XAML语法.

而不是这个:

<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
...
{Binding SomeBooleanProperty, Converter={StaticResource BooleanToVisibilityConverter}}
Run Code Online (Sandbox Code Playgroud)

你可以这样:

{Binding SomeBooleanProperty, Converter={my:BoolToVisibilityConverter}}
Run Code Online (Sandbox Code Playgroud)

在我看来,这不值得.如果您对保存击键感到困扰,可以缩短用于引用转换器的键:

<BooleanToVisibilityConverter x:Key="btvc" />
...
{Binding SomeBooleanProperty, Converter={StaticResource my:btvc}}
Run Code Online (Sandbox Code Playgroud)

由于ProvideValue标记扩展的方法是实例方法,因此只有在创建了类的实例后才能调用它.由于该类是标记扩展和转换器,因此代码的两种变体每次都会创建一个转换器.唯一的区别是第一个变体将始终返回相同的转换器:但是,它不会阻止创建另一个转换器.


Alf*_*fie 6

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

...
Visibility="{Binding Property, 
            Converter={cnv:CustomNullToVisibilityConverter 
                       NotNullValue=Visible, NullValue=Collapsed}}" />
...
Run Code Online (Sandbox Code Playgroud)

请务必在中引用转换器的名称空间.xaml


编辑:

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

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

<cnv:CustomNullToVisibilityConverter x:Key="NullToVisibilityConverter"
        NotNullValue=Visible, NullValue=Collapsed />
...
Visibility="{Binding Property, Converter={StaticResource NullToVisibilityConverter}" />
...
Run Code Online (Sandbox Code Playgroud)