为了减少多余的XAML标记,我尝试将一个radiobutton类型的选择控件一般填充,即我使用枚举为ItemsControl
的{{1}}并创建一个显示哪个项目的DataTemplate通过检查项目的枚举值是否与当前设置相同来选择。
仅使用简单的转换器或DataTrigger无法完成,因为需要两个绑定,所以我创建了一个通用ItemsSource
来检查是否相等:
MutliValueConverter
<CheckBox.Visibility>
<MultiBinding Converter="{StaticResource EqualityComparisonConv}">
<Binding Path="Key"/>
<Binding Path="DisplayMode_Current" Source="{x:Static local:App.Settings}"/>
</MultiBinding>
</CheckBox.Visibility>
这里显而易见的问题是转换器返回一个布尔值,我需要首先转换为public class EqualityComparisonConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 2) throw new Exception("At least two inputs are needed for comparison");
bool output = (bool)values.Skip(1).Aggregate(values[0], (x1, x2) => { return x1.Equals(x2); });
return output;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
#endregion
}
。
仅使用转换器将MultiBinding包装在另一个绑定中不起作用,因为属性不是依赖项属性(因此不能为它们分配绑定)。我可以想到一些解决方法,比如将bool存储在某个Visibility
属性中,所以我可以将其用作新的绑定源,但我会更喜欢这样的事情:
Tag
当原始绑定发生更改时,此类需要更新其输出,并且需要能够将其输出值公开给<CheckBox.Visibility>
<local:PipeConverter Converter="{StaticResource BooleanToVisibilityConv}">
<MultiBinding Converter="{StaticResource EqualityComparisonConv}">
<Binding Path="Key"/>
<Binding Path="DisplayMode_Current" Source="{x:Static local:App.Settings}"/>
</MultiBinding>
</local:PipeConverter>
</CheckBox.Visibility>
属性,但我不知道如何实现。遇到的一个问题是需要依赖属性,因此继承自Visibility
会很好,但继承自Binding类也是有意义的,因为PipeConverter应该绑定并需要设置为值另一个依赖属性。
答案 0 :(得分:3)
基于这个想法(参见publicgk's answer,option C),人们可以创建一个包含一系列转换器的转换器,这些转换器在内部按顺序使用,我编写了一个适合我需要的伪劣实现。即我可以在开头使用MultiValueConverter并将输出传输到正常转换器列表中:
[ContentProperty("Converters")]
public class GroupConverter : IValueConverter, IMultiValueConverter
{
private IMultiValueConverter _multiValueConverter;
public IMultiValueConverter MultiValueConverter
{
get { return _multiValueConverter; }
set { _multiValueConverter = value; }
}
private List<IValueConverter> _converters = new List<IValueConverter>();
public List<IValueConverter> Converters
{
get { return _converters; }
set { _converters = value; }
}
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return GroupConvert(value, Converters);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return GroupConvertBack(value, Converters.ToArray().Reverse());
}
private static object GroupConvert(object value, IEnumerable<IValueConverter> converters)
{
return converters.Aggregate(value, (acc, conv) => { return conv.Convert(acc, typeof(object), null, null); });
}
private static object GroupConvertBack(object value, IEnumerable<IValueConverter> converters)
{
return converters.Aggregate(value, (acc, conv) => { return conv.ConvertBack(acc, typeof(object), null, null); });
}
#endregion
#region IMultiValueConverter Members
private InvalidOperationException _multiValueConverterUnsetException =
new InvalidOperationException("To use the converter as a MultiValueConverter the MultiValueConverter property needs to be set.");
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (MultiValueConverter == null) throw _multiValueConverterUnsetException;
var firstConvertedValue = MultiValueConverter.Convert(values, targetType, parameter, culture);
return GroupConvert(firstConvertedValue, Converters);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
if (MultiValueConverter == null) throw _multiValueConverterUnsetException;
var tailConverted = GroupConvertBack(value, Converters.ToArray().Reverse());
return MultiValueConverter.ConvertBack(tailConverted, targetTypes, parameter, culture);
}
#endregion
}
(正如您所看到的,我几乎完全忽略了ConverterParameters
,TargetTypes
和CultureInfo
参数,ConvertBack
方法未经测试,所以我不这样做建议任何人实际使用它。)
XAML用法:
<vc:GroupConverter MultiValueConverter="{StaticResource EqualityComparisonConv}">
<StaticResource ResourceKey="BoolToVisibilityConv"/>
</vc:GroupConverter>
答案 1 :(得分:2)
三种选择:
选项A :将您的bool转换为多值转换器中的可见性(仅一行)
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 2)
throw new Exception("At least two inputs are needed for comparison");
bool output = (bool)values.Skip(1).Aggregate(values[0], (x1, x2) =>
{ return x1.Equals(x2); });
return output ? Visibility.Visible : Visibility.Collapsed;
}
选项B :以编程方式使用现有的booltovisibilityconverter
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 2)
throw new Exception("At least two inputs are needed for comparison");
bool output = (bool)values.Skip(1).Aggregate(values[0], (x1, x2) =>
{ return x1.Equals(x2); });
System.Windows.Controls.BooleanToVisibilityConverter booltovisibilityconverter = new System.Windows.Controls.BooleanToVisibilityConverter();
return booltovisibilityconverter.Convert(output, System.Type.GetType("System.Boolean"), parameter, culture);
}
PS:您可能希望缓存booltovisibilityconverter而不是每次都创建它。
选项C :管道您的转换器
Piping Value Converters in WPF
PS:要知道这篇文章很老了。