54

我有一个要显示/隐藏的控件,具体取决于布尔值。

我有一个NegatedBooleanConverter(将 true 切换为 false,反之亦然),我需要先运行这个转换器。我有一个BooleanToVisibilityConverter,我需要在NegatedBoolConverter.

我该如何解决这个问题?我想在 XAML 中执行此操作。

编辑:这是一个可能的解决方案。

这似乎行不通。它首先使用单独的转换器转换值,然后对转换后的值执行一些操作。

我需要的是:

  • 使用第一个转换器转换值(这给出了转换的值)。
  • 使用第二个转换器转换convertedValue,这就是我需要的结果。
4

11 回答 11

69

这就是我所做的:

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}" />

我认为AMultiValueConverter也可能。也许我稍后会尝试。

于 2009-10-20T14:28:14.887 回答
34

扩展 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> { }
于 2011-12-05T22:09:11.143 回答
8

在这种情况下,您不需要转换器链。你只需要一个可配置的转换器。这类似于 Carlo 上面的回答,但明确定义了真值和假值(这意味着您可以使用相同的转换器进行HiddenVisible转换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" />
于 2015-02-04T08:43:18.793 回答
4

我们在项目中所做的是制作一个常规的BooleanToVisibilityConverter,表示转换器采用一个参数(任何东西,a string,an 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
}
于 2009-10-20T14:21:56.293 回答
3

再次回答我自己的问题:我多年来一直在使用这个解决方案:

WPF 中的管道值转换器 - CodeProject

它制作了 2 个现有转换器的新转换器,首先调用第一个,然后调用第二个,依此类推。

我对这个解决方案很满意。

于 2016-08-24T05:54:21.563 回答
1

在这一点上,我想建议ValueConverters.NET ( NuGet ),它有大量有用ValueConverter的 s,包括ValueConverterGroup可用于组合ValueConverters 的。

BoolToValueConverters 还提供字段来定义TrueValueFalseValue以及是否输入IsInverted,因此ValueConverterGroup在大多数情况下甚至不需要 a 。

只是为了说明生活可以变得多么容易,这里有一个示例演示,它显示了一个转换器,如果绑定不为空,它会显示一个元素:

<Window ...
        xmlns:vc="clr-namespace:ValueConverters;assembly=ValueConverters"
        ...>
...
    <vc:ValueConverterGroup x:Key="IsNotNullToVisibilityConverter">
      <vc:NullToBoolConverter IsInverted="True" />
      <vc:BoolToVisibilityConverter />
    </vc:ValueConverterGroup>

ValueConverters 是在许多 WPF 应用程序中重新发明轮子的主要示例。为什么必须这样?

复杂的事情通常可以用StyleTriggers 或在ViewModels 逻辑本身内解决。

我几乎从未需要构建自定义转换器。在我看来,WPF 已经有足够的工程师要求了。

于 2021-11-09T03:33:08.733 回答
0

我刚刚创建了我所说ReversedBooleanToVisibilityConverter的基本上做那些 2 会为你做的事情,但一步。

于 2009-10-20T13:43:16.653 回答
0

为了解决这个特定问题,您可以编写自己的转换器,而不是使用两个转换器BoolToVisibilityConverter,使用ConverterParameter(as a bool) 来确定是否否定原始布尔值。

于 2009-10-20T13:47:31.817 回答
0

就我个人而言,我只会制作 1 个进行完整转换的单个转换器。除非您在其他地方迫切需要转换器(如否定),否则如果在一个地方进行一次转换,则维护(imo)会更容易。

于 2009-10-20T13:48:19.473 回答
0

我认为您可能想在这里使用 Multiconverter 而不是两个单独的转换器。您应该能够重用现有转换器的逻辑。查看此讨论作为开始。

于 2009-10-20T14:16:21.320 回答
0

以下是Natriummetao答案的组合,可节省您一些时间:

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}}"/>
于 2020-02-24T07:52:31.010 回答