如何反转BooleanToVisibilityConverter?


143

BooleanToVisibilityConverter在WPF中使用Visibility,将控件的属性绑定到Boolean。效果很好,但是我希望其中一个控件可以隐藏boolean是否为true,并显示是否为false


注意:从beta 4开始-silverlight不包含BooleanToVisibility-因此您仍然需要自己实现它
Simon_Weaver 2009年


我不敢相信他们没有实现某些转换器参数来执行此类操作。
卡米尔

Answers:



250

通过使用通用IValueConverter实现,可以将布尔值转换为true和false的可配置目标值,而不是取反。下面是一种这样的实现:

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);
    }
}

接下来,在以下位置T将其子类化Visibility

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

最后,这是BooleanToVisibilityConverter在XAML中使用上述方法并将其配置为例如Collapsed用于true和Visiblefalse的方式:

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

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


我可能会缺少一些东西,但是您是否只需要一个否定的财产?stackoverflow.com/questions/534575/...
OscarRyz

9
@OscarRyz:使用更复杂的UI时,这开始给视图模型添加很多非常烦人的杂物,更不用说理论上必须进行单元测试才能保持代码覆盖率的另一个属性。查看模型不应该得到的是接近视图的实施细则,否则,你可能也只是有Visibility在您的视图模型属性。
亚伦诺特,2012年

这很简单,但很有帮助。谢谢@AtifAziz。
TheLastGIS

48
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>

4
else if (value is bool?)一部分,ReSharper告诉我“表达总是错误的”。另外,该if (flag)部分可以更简洁地重写为return flag ? Visibility.Visible : Visibility.Collapsed;
Danilo Bargen 2012年

1
我可能会缺少一些东西,但是您是否只需要一个否定的财产?stackoverflow.com/questions/534575/…–
OscarRyz

1
var nullable = (bool?)value; flag = nullable.GetValueOrDefault();可以变得更短,更简单:flag = (bool?)value ?? false;
ANeves 2014年

45

自己编写是目前最好的解决方案。这是一个既可以正常也可以反向使用的转换器示例。如果您对此有任何疑问,请询问。

[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>

2
只是一件事。xaml代码“ Binding IsRunning”,对象“ IsRunning”的源代码或值在哪里?
WhatsUP 2011年

IsRunning是我的视图模型上的一个属性。这段代码的内容很长,但缺点是我在运行一些计算时需要隐藏一些东西,而其他东西则没有隐藏。我创建了此转换器以使其实现,因此我不必在ViewModel上具有多个属性。
Michael Hohlios 2011年

2
您可以BooleanToVisibilityConverter通过检查参数是否为null 来替代常规:Parameter direction = Parameter.Normal; if (parameter != null) direction = (Parameter)Enum.Parse(typeof(Parameter), (string)parameter);
JCH2k 2014年

20

Codeplex 上还有WPF转换器项目。他们在他们的文档中说,您可以使用其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>

1
WPF转换器现在包括一个可以反转的BooleanToVisibilityConverter。
vinod

17

使用xaml控件可见性属性绑定ViewModel布尔值(IsButtonVisible)的另一种方法。没有编码,没有转换,只是样式。

<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>

15

还是真正的懒人方式,只需利用已有的内容并将其翻转:

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;
    }
}

5

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

<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>

3

我刚刚对此发表了一篇文章。我使用了与Michael Hohlios相似的想法。只是,我使用属性而不是使用“对象参数”。



我认为,在WPF中使用属性将可见性绑定到bool值可以使其更具可读性。

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

只是我自己的评论的后续活动。如果使用“属性”,则要创建转换器,必须创建一个单独的对象,一个是“反向”对象,另一个不是。如果使用参数,则可以将一个对象用于多个项目,但是如果不注意,可能会造成混淆。因此,两者都有优点和缺点。
Rhyous 2011年

我发现这对于实现布尔到颜色转换器非常有帮助。谢谢
Federinik

3

这是我写的并且经常使用的。它使用一个布尔型转换器参数来指示是否反转该值,然后使用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

2

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

基于以下事实,我们需要区分六个不同的情况:

  • 正确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'}"

我认为参数很容易记住。

希望它能帮助到别人。


2

您可以使用QuickConverter

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

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

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

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


1

写你自己的转换。

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

0

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

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();
  }
}

0

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

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>


0

与其编写您自己的代码/重新发明,不如考虑使用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在许多其他情况下也非常有用。


-2

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

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

<!-- 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); }
}

而且效果很好!

我想念什么吗?


7
您认为这是一个更简单的解决方案,对于单个属性甚至可能是这种情况(对于多个属性而言,它不可重用,您必须为每个属性都实现它)。我觉得这对实现来说是错误的地方,因为它与viewmodel / codeBehind和视图无关。
Mike Fuchs 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.