WPF:如何在 1 个绑定中使用 2 个转换器?
Posted
技术标签:
【中文标题】WPF:如何在 1 个绑定中使用 2 个转换器?【英文标题】:WPF: how to use 2 converters in 1 binding? 【发布时间】:2010-12-08 08:07:09 【问题描述】:我有一个要显示/隐藏的控件,具体取决于布尔值。
我有一个NegatedBooleanConverter
(将 true 切换为 false,反之亦然),我需要先运行此转换器。
我有一个BooleanToVisibilityConverter
,我需要在NegatedBoolConverter
之后运行这个转换器。
我该如何解决这个问题?我想在 XAML 中执行此操作。
编辑:this is a possible solution.
这似乎不起作用。它首先使用单独的转换器转换值,然后对转换后的值进行处理。
我需要的是:
用第一个转换器转换值(这给出了convertedValue)。 用第二个转换器转换convertedValue,这就是我需要的结果。【问题讨论】:
是的,您链接到的解决方案可能是最好的... 另见Chaining multiple converters in XAML Town 说得最好here,他的解决方案让你可以链接任意数量,类似于 jberger 的答案,但这个更优雅,实现更短 【参考方案1】:在这一点上,我想推荐ValueConverters.NET (NuGet),它有大量有用的ValueConverter
s,包括可用于组合ValueConverter
s 的ValueConverterGroup
。
BoolToValueConverter
s 还提供定义TrueValue
、FalseValue
以及输入IsInverted
的字段,因此在大多数情况下甚至不需要ValueConverterGroup
。
只是为了说明生活可以变得多么容易,这里有一个示例演示,它显示了一个转换器,如果绑定不为空,则显示一个元素:
<Window ...
xmlns:vc="clr-namespace:ValueConverters;assembly=ValueConverters"
...>
...
<vc:ValueConverterGroup x:Key="IsNotNullToVisibilityConverter">
<vc:NullToBoolConverter IsInverted="True" />
<vc:BoolToVisibilityConverter />
</vc:ValueConverterGroup>
ValueConverter
s 是在许多 WPF 应用程序中重新发明***的典型例子。为什么必须这样?
通常也可以使用StyleTrigger
s 或ViewModel
s 逻辑本身来解决复杂的问题。
我几乎从未需要构建自定义转换器。在我看来,WPF 已经有足够的工程师需求了。
【讨论】:
【参考方案2】:这就是我所做的:
public class CombiningConverter : IValueConverter
public IValueConverter Converter1 get; set;
public IValueConverter Converter2 get; set;
public object Convert(
object value, Type targetType, object parameter, CultureInfo culture)
object convertedValue =
Converter1.Convert(value, targetType, parameter, culture);
return Converter2.Convert(
convertedValue, targetType, parameter, culture);
public object ConvertBack(
object value, Type targetType, object parameter, CultureInfo culture)
throw new NotImplementedException();
我这样称呼它:
<converters:CombiningConverter
x:Key="negatedBoolToVisibilityConverter"
Converter1="StaticResource NegatedBooleanConverter"
Converter2="StaticResource BoolToVisibilityConverter" />
我认为MultiValueConverter
也可能是可能的。也许我稍后会尝试。
【讨论】:
【参考方案3】:以下是Natrium 和metao 的组合答案,可为您节省一些时间:
public class ComparisonConverter : IValueConverter
public object TrueValue get; set; = true;
public object FalseValue get; set; = false;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
return value?.Equals(parameter) == true? TrueValue : FalseValue;
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
return value?.Equals(TrueValue) == true ? parameter : Binding.DoNothing;
以及你如何使用它:
<converter:ComparisonConverter x:Key="ComparisonConverter" />
<converter:ComparisonConverter TrueValue="x:Static Visibility.Visible"
FalseValue="x:Static Visibility.Collapsed"
x:Key="ComparisonToVisibilityConverter" />
...
<RadioButton IsChecked="Binding Type, ConverterParameter=x:Static entities:LimitType.MinMax, Converter=StaticResource ComparisonConverter"/>
<TextBox Visibility="Binding Type, ConverterParameter=x:Static entities:LimitType.MinMax, Converter=StaticResource ComparisonToVisibilityConverter"/>
【讨论】:
【参考方案4】:我刚刚创建了我称之为 ReversedBooleanToVisibilityConverter
的东西,基本上可以完成这 2 个操作,但只需一步完成。
【讨论】:
是的,这将是一个可能的解决方案,但我更喜欢这样的解决方案,即我可以重复使用当前的转换器,而无需重新发明***。如果存在该解决方案...【参考方案5】:为了解决这个特定问题,您可以编写自己的BoolToVisibilityConverter
,而不是使用两个转换器,它使用ConverterParameter
(作为bool
)来确定是否否定原始布尔值。
【讨论】:
是的,这将是一个可能的解决方案,但我更喜欢这样的解决方案,即我可以重复使用当前的转换器而无需重新发明***。如果该解决方案存在...【参考方案6】:再次回答我自己的问题:多年来我一直在使用这个解决方案:
Piping Value Converters in WPF - CodeProject
它使用 2 个现有转换器创建一个新转换器,首先调用第一个,然后调用第二个,依此类推。
我对这个解决方案很满意。
【讨论】:
【参考方案7】:我们在项目中所做的是制作一个常规的BooleanToVisibilityConverter
,表示转换器采用一个参数(任何参数,string
、int
、bool
,等等)。如果设置了参数,它会反转结果,如果没有,它会吐出常规结果。
public class BooleanToVisibilityConverter : IValueConverter
#region IValueConverter Members
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
bool? isVisible = value as bool?;
if (parameter != null && isVisible.HasValue)
isVisible = !isVisible;
if (isVisible.HasValue && isVisible.Value == true)
return Visibility.Visible;
else
return Visibility.Collapsed;
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
throw new System.NotImplementedException();
#endregion
【讨论】:
如何在xaml中调用这个转换器?【参考方案8】:在这种情况下,您不需要转换器链。你只需要一个可配置的转换器。这与上面 Carlo 的回答类似,但明确定义了 true 和 false 值(这意味着您可以对 Hidden
、Visible
或 Collapsed
转换使用相同的转换器)。
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BoolToVisibilityConverter : IValueConverter
public Visibility TrueValue get; set;
public Visibility FalseValue get; set;
public BoolToVisibilityConverter()
// set defaults
FalseValue = Visibility.Hidden;
TrueValue = Visibility.Visible;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
return (bool)value ? TrueValue : FalseValue;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
throw new NotImplementedException();
然后在 XAML 中:
<BoolToVisibilityConverter x:Key="BoolToVisibleConverter"
FalseValue="Hidden"
TrueValue="Visible" />
【讨论】:
如果您可以使用 XAML 2009,您也可以将其设为通用。属性语法:Converter=c:BooleanConverter(Visibility) True=Visible, False=Collapsed
元素语法:<c:BooleanConverter x:TypeArguments="FontWeight" True="Bold" False="Normal" />
如果您不能使用 XAML 2009,您仍然可以将基类设为泛型,但您需要为每个泛型类型提供具体的派生类。【参考方案9】:
扩展 Natrium 的最佳答案...
XAML
<conv:ConverterChain x:Key="convBoolToInverseToVisibility">
<conv:BoolToInverseConverter />
<BooleanToVisibilityConverter />
</conv:ConverterChain>
类
/// <summary>Represents a chain of <see cref="IValueConverter"/>s to be executed in succession.</summary>
[ContentProperty("Converters")]
[ContentWrapper(typeof(ValueConverterCollection))]
public class ConverterChain : IValueConverter
private readonly ValueConverterCollection _converters= new ValueConverterCollection();
/// <summary>Gets the converters to execute.</summary>
public ValueConverterCollection Converters
get return _converters;
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
return Converters
.Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameter, culture));
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
return Converters
.Reverse()
.Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameter, culture));
#endregion
/// <summary>Represents a collection of <see cref="IValueConverter"/>s.</summary>
public sealed class ValueConverterCollection : Collection<IValueConverter>
【讨论】:
这个article 的解决方案提供了运行时类型检查。 这会将错误的 targetType 传递给转换器。它将目标 targetType 传递给所有转换器,即使在开放问题的场景中也是不正确的。当 targetType 实际上是“bool”时,“Visibility”的类型被传递给第一个转换器。 @JakeBerger,我认为你应该使用 ConvertBack 到 ConverBack 函数?【参考方案10】:我认为您可能希望在此处使用 Multiconverter 而不是两个单独的转换器。您应该能够重用现有转换器的逻辑。查看this discussion 开始。
【讨论】:
【参考方案11】:就我个人而言,我只会制作 1 个进行完整转换的单个转换器。除非您在其他地方迫切需要转换器(如否定),否则如果在一个地方完成一次转换,则维护(imo)会更容易。
【讨论】:
是的,这将是一个可能的解决方案,但我更喜欢这样的解决方案,即我可以重复使用当前的转换器而无需重新发明***。如果该解决方案存在...以上是关于WPF:如何在 1 个绑定中使用 2 个转换器?的主要内容,如果未能解决你的问题,请参考以下文章