最近我读到了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创建一个这个转换器的新实例,对吗?
答案 0 :(得分:7)
在这种情况下,标记扩展提供的唯一(轻微)优势是更简洁的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
方法是实例方法,因此只有在创建了类的实例后才能调用它。由于该类是标记扩展和转换器,因此代码的两种变体每次都会创建一个转换器。唯一的区别是第一个变体将始终返回相同的转换器:但是,它不会阻止另一个转换器被创建。
答案 1 :(得分: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();
}
}
用法:
...
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}" />
...