【问题标题】:How do I invert BooleanToVisibilityConverter?如何反转 BooleanToVisibilityConverter?
【发布时间】:2010-10-06 18:45:40
【问题描述】:

我在 WPF 中使用BooleanToVisibilityConverter 将控件的Visibility 属性绑定到Boolean。这很好用,但如果布尔值为true,我希望隐藏其中一个控件,并显示它是否为false

【问题讨论】:

标签: .net wpf binding visibility


【解决方案1】:

您可以通过使用通用的IValueConverter 实现而不是反转来实现相同的目标,该实现可以将布尔值转换为可配置 目标值以表示真假。下面是一个这样的实现:

public class BooleanConverter<T> : IValueConverter
{
    public BooleanConverter(T trueValue, T falseValue)
    {
        True = trueValue;
        False = falseValue;
    }

    public T True { get; set; }
    public T False { get; set; }

    public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value is bool && ((bool) value) ? True : False;
    }

    public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value is T && EqualityComparer<T>.Default.Equals((T) value, True);
    }
}

接下来,在TVisibility 的地方对其进行子类化:

public sealed class BooleanToVisibilityConverter : BooleanConverter<Visibility>
{
    public BooleanToVisibilityConverter() : 
        base(Visibility.Visible, Visibility.Collapsed) {}
}

最后,您可以在 XAML 中使用上面的 BooleanToVisibilityConverter 并将其配置为,例如,使用 Collapsed 表示 true,使用 Visible 表示 false:

<Application.Resources>
    <app:BooleanToVisibilityConverter 
        x:Key="BooleanToVisibilityConverter" 
        True="Collapsed" 
        False="Visible" />
</Application.Resources>

当您想要绑定到名为 IsHidden 而不是 IsVisible 的布尔属性时,此反转非常有用。

【讨论】:

  • 我可能遗漏了一些东西,但你不只需要一个否定的属性吗? stackoverflow.com/questions/534575/…
  • @OscarRyz:对于更复杂的 UI,这开始给视图模型添加很多非常烦人的混乱,更不用说理论上您必须进行单元测试以保持代码覆盖率的另一个属性。视图模型不应该让 接近视图的实现细节,否则你可能只需要在视图模型中有 Visibility 属性。
  • 这很简单,但非常有用。谢谢@AtifAziz。
【解决方案2】:

自己编写是目前最好的解决方案。这是一个转换器的示例,它可以同时进行正常和反转。如果您对此有任何问题,请询问。

[ValueConversion(typeof(bool), typeof(Visibility))]
public class InvertableBooleanToVisibilityConverter : IValueConverter
{
    enum Parameters
    {
        Normal, Inverted
    }

    public object Convert(object value, Type targetType,
                          object parameter, CultureInfo culture)
    {
        var boolValue = (bool)value;
        var direction = (Parameters)Enum.Parse(typeof(Parameters), (string)parameter);

        if(direction == Parameters.Inverted)
            return !boolValue? Visibility.Visible : Visibility.Collapsed;

        return boolValue? Visibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        return null;
    }
}
<UserControl.Resources>
  <Converters:InvertableBooleanToVisibilityConverter x:Key="_Converter"/>
</UserControl.Resources>

<Button Visibility="{Binding IsRunning, Converter={StaticResource _Converter}, ConverterParameter=Inverted}">Start</Button>

【讨论】:

  • 只是想知道一件事。 xaml 代码“Binding IsRunning”,对象“IsRunning”的源代码或值在哪里?
  • IsRunning 是我的视图模型上的一个属性。这段代码的上下文很长,但不足之处是我在运行一些计算时需要隐藏一些东西,而其他一些东西没有隐藏。我创建了这个转换器来实现它,这样我就不必在我的视图模型上有多个属性。
  • 您可以通过检查参数是否为空来使其成为普通BooleanToVisibilityConverter 的直接替换:Parameter direction = Parameter.Normal; if (parameter != null) direction = (Parameter)Enum.Parse(typeof(Parameter), (string)parameter);
【解决方案3】:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

public sealed class BooleanToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var flag = false;
        if (value is bool)
        {
            flag = (bool)value;
        }
        else if (value is bool?)
        {
            var nullable = (bool?)value;
            flag = nullable.GetValueOrDefault();
        }
        if (parameter != null)
        {
            if (bool.Parse((string)parameter))
            {
                flag = !flag;
            }
        }
        if (flag)
        {
            return Visibility.Visible;
        }
        else
        {
            return Visibility.Collapsed;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var back = ((value is Visibility) && (((Visibility)value) == Visibility.Visible));
        if (parameter != null)
        {
            if ((bool)parameter)
            {
                back = !back;
            }
        }
        return back;
    }
}

然后将 true 或 false 作为 ConverterParameter 传递

       <Grid.Visibility>
                <Binding Path="IsYesNoButtonSetVisible" Converter="{StaticResource booleanToVisibilityConverter}" ConverterParameter="true"/>
        </Grid.Visibility>

【讨论】:

  • else if (value is bool?) 部分,ReSharper 告诉我“表达式总是错误的”。此外,if (flag) 部分可以更简洁地重写为return flag ? Visibility.Visible : Visibility.Collapsed;
  • 我可能遗漏了一些东西,但你不只需要一个否定的属性吗? stackoverflow.com/questions/534575/…
  • var nullable = (bool?)value; flag = nullable.GetValueOrDefault(); 可以变得更短更简单:flag = (bool?)value ?? false;
【解决方案4】:

实现您自己的 IValueConverter 实现。示例实现位于

http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx

在您的 Convert 方法中,让它返回您想要的值而不是默认值。

【讨论】:

    【解决方案5】:

    Codeplex 上还有 WPF Converters 项目。在他们的文档中,他们说您可以使用他们的 MapConverter 将 Visibility 枚举转换为 bool

    <Label>
        <Label.Visible>
            <Binding Path="IsVisible">
                <Binding.Converter>
                    <con:MapConverter>
                        <con:Mapping From="True" To="{x:Static Visibility.Visible}"/>
                        <con:Mapping From="False" To="{x:Static Visibility.Hidden}"/>
                    </con:MapConverter>
                </Binding.Converter>
            </Binding>
        </Label.Visible>
    </Label>
    

    【讨论】:

    • WPF 转换器现在包括一个可以反转的 BooleanToVisibilityConverter。
    【解决方案6】:

    将 ViewModel 布尔值 (IsButtonVisible) 与 xaml 控件可见性属性绑定的另一种方法。 无需编码,无需转换,只需样式化。

    <Style TargetType={x:Type Button} x:Key="HideShow">
       <Style.Triggers>
          <DataTrigger Binding="{Binding IsButtonVisible}" Value="False">
              <Setter Property="Visibility" Value="Hidden"/>
          </DataTrigger>
       </Style.Triggers>
    </Style>
    
    <Button Style="{StaticResource HideShow}">Hello</Button>
    

    【讨论】:

      【解决方案7】:

      或者真正的懒人方式,利用已有的东西翻转它:

      public class InverseBooleanToVisibilityConverter : IValueConverter
      {
          private BooleanToVisibilityConverter _converter = new BooleanToVisibilityConverter();
      
          public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
          {
              var result = _converter.Convert(value, targetType, parameter, culture) as Visibility?;
              return result == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed;
          }
      
          public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
          {
              var result = _converter.ConvertBack(value, targetType, parameter, culture) as bool?;
              return result == true ? false : true;
          }
      }
      

      【讨论】:

        【解决方案8】:

        如果你不喜欢编写自定义转换器,你可以使用数据触发器来解决这个问题:

        <Style.Triggers>
                <DataTrigger Binding="{Binding YourBinaryOption}" Value="True">
                         <Setter Property="Visibility" Value="Visible" />
                </DataTrigger>
                <DataTrigger Binding="{Binding YourBinaryOption}" Value="False">
                         <Setter Property="Visibility" Value="Collapsed" />
                </DataTrigger>
        </Style.Triggers>
        

        【讨论】:

          【解决方案9】:

          我刚刚发了一篇关于这个的帖子。我使用了与 Michael Hohlios 类似的想法。只是,我使用了属性而不是使用“对象参数”。

          Binding Visibility to a bool value in WPF

          在我看来,使用属性使其更具可读性。

          <local:BoolToVisibleOrHidden x:Key="BoolToVisConverter" Collapse="True" Reverse="True" />
          

          【讨论】:

          • 只是对我自己的评论的跟进。如果您使用属性,如果要创建转换器,则必须创建一个单独的对象,一个是反向的,一个不是。如果使用参数,可以将一个对象用于多个项目,但如果不注意可能会造成混乱。所以两者各有利弊。
          • 我发现这对实现布尔到颜色转换器非常有帮助。谢谢
          【解决方案10】:

          这是我写过并经常使用的一个。它使用布尔转换器参数指示是否反转值,然后使用 XOR 执行否定:

          [ValueConversion(typeof(bool), typeof(System.Windows.Visibility))]
          public class BooleanVisibilityConverter : IValueConverter
          {
              System.Windows.Visibility _visibilityWhenFalse = System.Windows.Visibility.Collapsed;
          
              /// <summary>
              /// Gets or sets the <see cref="System.Windows.Visibility"/> value to use when the value is false. Defaults to collapsed.
              /// </summary>
              public System.Windows.Visibility VisibilityWhenFalse
              {
                  get { return _visibilityWhenFalse; }
                  set { _visibilityWhenFalse = value; }
              }
          
              public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
              {
                  bool negateValue;
                  Boolean.TryParse(parameter as string, out negateValue);
          
                  bool val = negateValue ^ System.Convert.ToBoolean(value); //Negate the value when negateValue is true using XOR
                  return val ? System.Windows.Visibility.Visible : _visibilityWhenFalse;
              }
          
              public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
              {
                  bool negateValue;
                  Boolean.TryParse(parameter as string, out negateValue);
          
                  if ((System.Windows.Visibility)value == System.Windows.Visibility.Visible)
                      return true ^ negateValue;
                  else
                      return false ^ negateValue;
              }
          }
          

          这是一个 XOR 真值表供参考:

                  XOR
                  x  y  XOR
                  ---------
                  0  0  0
                  0  1  1
                  1  0  1
                  1  1  0
          

          【讨论】:

            【解决方案11】:

            我一直在寻找更一般的答案,但找不到。我写了一个转换器,可以帮助别人。

            这是基于我们需要区分六种不同的情况:

            • 真 2 可见,假 2 隐藏
            • 真 2 可见,假 2 折叠
            • 真 2 隐藏,假 2 可见
            • 真 2 折叠,假 2 可见
            • 真 2 隐藏,假 2 折叠
            • 真 2 折叠,假 2 隐藏

            这是我对前 4 个案例的实现:

            [ValueConversion(typeof(bool), typeof(Visibility))]
            public class BooleanToVisibilityConverter : IValueConverter
            {
                enum Types
                {
                    /// <summary>
                    /// True to Visible, False to Collapsed
                    /// </summary>
                    t2v_f2c,
                    /// <summary>
                    /// True to Visible, False to Hidden
                    /// </summary>
                    t2v_f2h,
                    /// <summary>
                    /// True to Collapsed, False to Visible
                    /// </summary>
                    t2c_f2v,
                    /// <summary>
                    /// True to Hidden, False to Visible
                    /// </summary>
                    t2h_f2v,
                }
                public object Convert(object value, Type targetType,
                                      object parameter, CultureInfo culture)
                {
                    var b = (bool)value;
                    string p = (string)parameter;
                    var type = (Types)Enum.Parse(typeof(Types), (string)parameter);
                    switch (type)
                    {
                        case Types.t2v_f2c:
                            return b ? Visibility.Visible : Visibility.Collapsed; 
                        case Types.t2v_f2h:
                            return b ? Visibility.Visible : Visibility.Hidden; 
                        case Types.t2c_f2v:
                            return b ? Visibility.Collapsed : Visibility.Visible; 
                        case Types.t2h_f2v:
                            return b ? Visibility.Hidden : Visibility.Visible; 
                    }
                    throw new NotImplementedException();
                }
            
                public object ConvertBack(object value, Type targetType,
                    object parameter, CultureInfo culture)
                {
                    var v = (Visibility)value;
                    string p = (string)parameter;
                    var type = (Types)Enum.Parse(typeof(Types), (string)parameter);
                    switch (type)
                    {
                        case Types.t2v_f2c:
                            if (v == Visibility.Visible)
                                return true;
                            else if (v == Visibility.Collapsed)
                                return false;
                            break;
                        case Types.t2v_f2h:
                            if (v == Visibility.Visible)
                                return true;
                            else if (v == Visibility.Hidden)
                                return false;
                            break;
                        case Types.t2c_f2v:
                            if (v == Visibility.Visible)
                                return false;
                            else if (v == Visibility.Collapsed)
                                return true;
                            break;
                        case Types.t2h_f2v:
                            if (v == Visibility.Visible)
                                return false;
                            else if (v == Visibility.Hidden)
                                return true;
                            break;
                    }
                    throw new InvalidOperationException();
                }
            }
            

            示例:

            Visibility="{Binding HasItems, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter='t2v_f2c'}"
            

            我觉得参数好记。

            希望它对某人有所帮助。

            【讨论】:

              【解决方案12】:

              您可以使用 QuickConverter

              使用 QuickConverter,您可以使用 BindingExpression 编写转换器逻辑

              这是一个反转的 BooleanToVisibility 转换器:

              Visibility="{qc:Binding '!$P ? Visibility.Visible : Visibility.Collapsed', P={Binding Example}}"
              

              您可以通过 NuGet 添加 QuickConverter。 查看设置文档。 链接:https://quickconverter.codeplex.com/

              【讨论】:

                【解决方案13】:

                编写您自己的转换。

                public class ReverseBooleanToVisibilityConverter : IValueConverter
                {
                    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
                   {
                       // your converter code here
                   }
                }
                

                【讨论】:

                  【解决方案14】:

                  与其编写自己的代码/重新发明,不如考虑使用CalcBinding

                  Automatic two way convertion of bool expression to Visibility and back if target property has such type: description
                  
                      <Button Visibility="{c:Binding !IsChecked}" /> 
                      <Button Visibility="{c:Binding IsChecked, FalseToVisibility=Hidden}" />
                  

                  CalcBinding 对于许多其他场景也非常有用。

                  【讨论】:

                    【解决方案15】:

                    一个简单的单向版本,可以像这样使用:

                    Visibility="{Binding IsHidden, Converter={x:Static Ui:Converters.BooleanToVisibility}, ConverterParameter=true}
                    

                    可以这样实现:

                    public class BooleanToVisibilityConverter : IValueConverter
                    {
                      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
                      {
                        var invert = false;
                    
                        if (parameter != null)
                        {
                          invert = Boolean.Parse(parameter.ToString());
                        }
                    
                        var booleanValue = (bool) value;
                    
                        return ((booleanValue && !invert) || (!booleanValue && invert)) 
                          ? Visibility.Visible : Visibility.Collapsed;
                      }
                    
                      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
                      {
                        throw new NotImplementedException();
                      }
                    }
                    

                    【讨论】:

                      【解决方案16】:

                      将所有内容转换为所有内容(布尔、字符串、枚举等):

                      public class EverythingConverterValue
                      {
                          public object ConditionValue { get; set; }
                          public object ResultValue { get; set; }
                      }
                      
                      public class EverythingConverterList : List<EverythingConverterValue>
                      {
                      
                      }
                      
                      public class EverythingConverter : IValueConverter
                      {
                          public EverythingConverterList Conditions { get; set; } = new EverythingConverterList();
                      
                          public object NullResultValue { get; set; }
                          public object NullBackValue { get; set; }
                      
                          public object Convert(object value, Type targetType,
                              object parameter, CultureInfo culture)
                          {
                              return Conditions.Where(x => x.ConditionValue.Equals(value)).Select(x => x.ResultValue).FirstOrDefault() ?? NullResultValue;
                          }
                          public object ConvertBack(object value, Type targetType,
                              object parameter, CultureInfo culture)
                          {
                              return Conditions.Where(x => x.ResultValue.Equals(value)).Select(x => x.ConditionValue).FirstOrDefault() ?? NullBackValue;
                          }
                      }
                      

                      XAML 示例:

                      <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                                      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                                      xmlns:conv="clr-namespace:MvvmGo.Converters;assembly=MvvmGo.WindowsWPF"
                                      xmlns:sys="clr-namespace:System;assembly=mscorlib">
                      
                      <conv:EverythingConverter x:Key="BooleanToVisibilityConverter">
                          <conv:EverythingConverter.Conditions>
                              <conv:EverythingConverterValue ResultValue="{x:Static Visibility.Visible}">
                                  <conv:EverythingConverterValue.ConditionValue>
                                      <sys:Boolean>True</sys:Boolean>
                                  </conv:EverythingConverterValue.ConditionValue>
                              </conv:EverythingConverterValue>
                              <conv:EverythingConverterValue ResultValue="{x:Static Visibility.Collapsed}">
                                  <conv:EverythingConverterValue.ConditionValue>
                                      <sys:Boolean>False</sys:Boolean>
                                  </conv:EverythingConverterValue.ConditionValue>
                              </conv:EverythingConverterValue>
                          </conv:EverythingConverter.Conditions>
                      
                      </conv:EverythingConverter>
                      
                      <conv:EverythingConverter x:Key="InvertBooleanToVisibilityConverter">
                          <conv:EverythingConverter.Conditions>
                              <conv:EverythingConverterValue ResultValue="{x:Static Visibility.Visible}">
                                  <conv:EverythingConverterValue.ConditionValue>
                                      <sys:Boolean>False</sys:Boolean>
                                  </conv:EverythingConverterValue.ConditionValue>
                              </conv:EverythingConverterValue>
                              <conv:EverythingConverterValue ResultValue="{x:Static Visibility.Collapsed}">
                                  <conv:EverythingConverterValue.ConditionValue>
                                      <sys:Boolean>True</sys:Boolean>
                                  </conv:EverythingConverterValue.ConditionValue>
                              </conv:EverythingConverterValue>
                          </conv:EverythingConverter.Conditions>
                      </conv:EverythingConverter>
                      
                      <conv:EverythingConverter x:Key="MarriedConverter" NullResultValue="Single">
                          <conv:EverythingConverter.Conditions>
                              <conv:EverythingConverterValue ResultValue="Married">
                                  <conv:EverythingConverterValue.ConditionValue>
                                      <sys:Boolean>True</sys:Boolean>
                                  </conv:EverythingConverterValue.ConditionValue>
                              </conv:EverythingConverterValue>
                              <conv:EverythingConverterValue ResultValue="Single">
                                  <conv:EverythingConverterValue.ConditionValue>
                                      <sys:Boolean>False</sys:Boolean>
                                  </conv:EverythingConverterValue.ConditionValue>
                              </conv:EverythingConverterValue>
                          </conv:EverythingConverter.Conditions>
                          <conv:EverythingConverter.NullBackValue>
                              <sys:Boolean>False</sys:Boolean>
                          </conv:EverythingConverter.NullBackValue>
                      </conv:EverythingConverter>
                      

                      【讨论】:

                        【解决方案17】:

                        我知道这已经过时了,但是,您不需要重新实现任何东西。

                        我所做的是像这样否定属性的值:

                        <!-- XAML code -->
                        <StackPanel Name="x"  Visibility="{Binding    Path=Specials, ElementName=MyWindow, Converter={StaticResource BooleanToVisibilityConverter}}"></StackPanel>    
                        <StackPanel Name="y"  Visibility="{Binding Path=NotSpecials, ElementName=MyWindow, Converter={StaticResource BooleanToVisibilityConverter}}"></StackPanel>        
                        

                        ....

                        //Code behind
                        public bool Specials
                        {
                            get { return (bool) GetValue(SpecialsProperty); }
                            set
                            {
                                NotSpecials= !value; 
                                SetValue(SpecialsProperty, value);
                            }
                        }
                        
                        public bool NotSpecials
                        {
                            get { return (bool) GetValue(NotSpecialsProperty); }
                            set { SetValue(NotSpecialsProperty, value); }
                        }
                        

                        而且效果很好!

                        我错过了什么吗?

                        【讨论】:

                        • 你认为这是一个更简单的解决方案,对于单个属性甚至可能是这种情况(它不能重复用于多个属性,你必须为每个属性实现它)。我觉得这是错误的实现地方,因为它与 viewmodel/codeBehind 以及与视图无关的一切。
                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 2020-08-25
                        • 1970-01-01
                        • 1970-01-01
                        • 2014-04-17
                        • 2016-06-25
                        • 2011-01-05
                        相关资源
                        最近更新 更多