【问题标题】:IValueConverter with MarkupExtension带有 MarkupExtension 的 IValueConverter
【发布时间】:2015-04-14 13:59:32
【问题描述】:

最近我读到了一个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}"/>

我习惯于使用来自以下资源的转换器:

<loc:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
...
<Button Content="Delete" Visibility="{Binding CanDelete, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BoolToVisibilityConverter}"/>

我现在的第一个问题是:更好的方法是什么?如果我使用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;        
    }
}

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

【问题讨论】:

    标签: c# wpf converter ivalueconverter markup-extensions


    【解决方案1】:

    使用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}" />
    ...
    

    【讨论】:

    • 感谢您最后给出了一个很好的 MarkupExtension 用法示例。
    【解决方案2】:

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

    而不是这个:

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

    你可以拥有这个:

    {Binding SomeBooleanProperty, Converter={my:BoolToVisibilityConverter}}
    

    在我看来,这并不值得。如果您为保存击键而烦恼,您可以缩短用于引用转换器的键:

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

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

    【讨论】:

      猜你喜欢
      • 2011-11-18
      • 2012-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-23
      • 2013-05-31
      相关资源
      最近更新 更多