Làm cách nào để đảo ngược BooleanToVisibilityConverter?


143

Tôi đang sử dụng một BooleanToVisibilityConverterWPF để ràng buộc thuộc Visibilitytính của điều khiển với a Boolean. Điều này hoạt động tốt, nhưng tôi muốn một trong các điều khiển để ẩn nếu boolean là true, và hiển thị nếu nó false.


lưu ý: kể từ phiên bản beta 4 - silverlight không bao gồm BooleanToVisibility - vì vậy bạn sẽ cần phải tự mình thực hiện nó
Simon_Weaver

Thêm một gợi ý sử dụng giọng nói để có được nghịch hỗ trợ visualstudio.uservoice.com/forums/121579-visual-studio-2015/...
Thraka

Tôi không thể tin rằng họ đã không thực hiện một số tham số chuyển đổi để làm những việc như vậy.
Kamil

Câu trả lời:



250

Thay vì đảo ngược, bạn có thể đạt được cùng một mục tiêu bằng cách sử dụng IValueConvertertriển khai chung có thể chuyển đổi giá trị Boolean thành giá trị đích có thể định cấu hình thành đúng và sai. Dưới đây là một trong những thực hiện như vậy:

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

Tiếp theo, phân lớp nó ở đâu TVisibility:

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

Cuối cùng, đây là cách bạn có thể sử dụng BooleanToVisibilityConverterở trên trong XAML và định cấu hình nó, ví dụ, sử dụng Collapsedcho đúng và Visiblesai:

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

Sự đảo ngược này rất hữu ích khi bạn muốn liên kết với một thuộc tính Boolean có tên IsHiddenlà trái ngược IsVisible.


Tôi có thể đang thiếu một cái gì đó, nhưng bạn không cần một tài sản bị phủ nhận? stackoverflow.com/questions/534575/
trộm

9
@OscarRyz: Với các UI phức tạp hơn, bắt đầu thêm rất nhiều sự lộn xộn thực sự gây khó chịu cho các mô hình xem, chưa kể đến một thuộc tính khác mà về mặt lý thuyết bạn phải kiểm tra đơn vị để duy trì phạm vi bảo hiểm mã. Xem mô hình không nên có để có được điều đó gần với chi tiết thi hành xem, nếu không bạn cũng có thể chỉ có Visibilitycác thuộc tính trong mô hình quan điểm của bạn.
Aaronaught

Điều này rất đơn giản, nhưng đáng kể hữu ích. Cảm ơn bạn @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;
    }
}

và sau đó chuyển đúng hoặc sai dưới dạng ConverterParameter

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

4
Về else if (value is bool?)phần mình, ReSharper nói với tôi "Biểu hiện luôn luôn sai". Ngoài ra, if (flag)phần có thể được viết lại chính xác hơn như return flag ? Visibility.Visible : Visibility.Collapsed;.
Danilo Bargen

1
Tôi có thể đang thiếu một cái gì đó, nhưng bạn không cần một tài sản bị phủ nhận? stackoverflow.com/questions/534575/
trộm

1
var nullable = (bool?)value; flag = nullable.GetValueOrDefault();có thể được thực hiện ngắn hơn và đơn giản hơn:flag = (bool?)value ?? false;
ANeves

45

Viết của riêng bạn là giải pháp tốt nhất cho bây giờ. Dưới đây là một ví dụ về Trình chuyển đổi có thể thực hiện cả hai cách Bình thường và Đảo ngược. Nếu bạn có bất kỳ vấn đề với điều này chỉ cần hỏi.

[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
Chỉ tự hỏi một điều. Mã xaml "Binding IsRasty", mã nguồn hoặc giá trị cho đối tượng "IsRasty" nằm ở đâu?
WhatUPUP

IsRasty là một tài sản trên viewmodel của tôi. Bối cảnh của mã này dài nhưng ngắn gọn là tôi cần phải ẩn đi điều gì đó khi tôi đang chạy một số tính toán và những thứ khác không bị ẩn. Tôi đã tạo trình chuyển đổi này để làm cho nó để tôi không phải có nhiều thuộc tính trên viewmodel của mình.
Michael Hohlios

2
Bạn có thể biến nó thành một thay thế thả xuống cho bình thường BooleanToVisibilityConverterbằng cách kiểm tra tham số cho null:Parameter direction = Parameter.Normal; if (parameter != null) direction = (Parameter)Enum.Parse(typeof(Parameter), (string)parameter);
JCH2k

20

Ngoài ra còn có dự án WPF Converters trên Codeplex. Trong tài liệu của họ, họ nói rằng bạn có thể sử dụng MapConverter của họ để chuyển đổi từ bảng liệt kê Hiển thị sang 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
Bộ chuyển đổi WPF hiện bao gồm BooleanToVisibilityConverter có thể đảo ngược.
vinod

17

Một cách nữa để Bind ViewModel Giá trị Boolean (IsButtonVisible) với thuộc tính Hiển thị kiểm soát xaml. Không mã hóa, Không chuyển đổi, chỉ cần tạo kiểu.

<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

Hoặc cách lười biếng thực sự, chỉ cần tận dụng những gì đã có và lật nó:

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

Nếu bạn không thích viết trình chuyển đổi tùy chỉnh, bạn có thể sử dụng trình kích hoạt dữ liệu để giải quyết vấn đề này:

<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

Tôi vừa làm một bài về điều này. Tôi đã sử dụng một ý tưởng tương tự như Michael Hohlios đã làm. Chỉ, tôi đã sử dụng Thuộc tính thay vì sử dụng "tham số đối tượng".

Khả năng hiển thị liên kết với giá trị bool trong WPF

bằng cách sử dụng thuộc tính làm cho nó dễ đọc hơn, theo ý kiến ​​của tôi.

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

Chỉ là một theo dõi trên bình luận của riêng tôi. Nếu bạn sử dụng Thuộc tính, bạn phải tạo một đối tượng riêng nếu bạn muốn tạo thành bộ chuyển đổi, một đối tượng là Đảo ngược và một đối tượng không. Nếu bạn sử dụng tham số, bạn có thể sử dụng một đối tượng cho nhiều mục, nhưng nó có thể gây nhầm lẫn nếu bạn không chú ý. Vì vậy, có những ưu và nhược điểm cho cả hai.
Rhyous

Tôi thấy điều này rất hữu ích trong việc hiện thực hóa các bộ chuyển đổi Boolean sang Colors. Cảm ơn bạn
Federinik

3

Đây là một cái tôi đã viết và sử dụng rất nhiều. Nó sử dụng tham số chuyển đổi boolean cho biết có đảo ngược giá trị hay không và sau đó sử dụng XOR để thực hiện phủ định:

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

Đây là bảng chân lý XOR để tham khảo:

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

2

Tôi đang tìm kiếm một câu trả lời tổng quát hơn, nhưng không thể tìm thấy nó. Tôi đã viết một công cụ chuyển đổi có thể giúp đỡ người khác.

Nó dựa trên thực tế là chúng ta cần phân biệt sáu trường hợp khác nhau:

  • Đúng 2 Hiển thị, Sai 2 Ẩn
  • Đúng 2 Hiển thị, Sai 2 Sụp đổ
  • Đúng 2 Ẩn, Sai 2 Hiển thị
  • Đúng 2 Sụp đổ, Sai 2 Hiển thị
  • Đúng 2 Ẩn, Sai 2 Sụp đổ
  • Đúng 2 Sụp đổ, Sai 2 Ẩn

Đây là cách thực hiện của tôi cho 4 trường hợp đầu tiên:

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

thí dụ:

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

Tôi nghĩ rằng các thông số là dễ nhớ.

Hy vọng nó sẽ giúp được ai đó.


2

Bạn có thể sử dụng QuickConverter .

Với QuickConverter, bạn có thể viết nội tuyến logic chuyển đổi bằng BindingExpression của bạn

Đây là một trình chuyển đổi BooleanToVisibility ngược:

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

Bạn có thể thêm QuickConverter qua NuGet. Có một cái nhìn vào các tài liệu để thiết lập. Liên kết: https://quickconverter.codeplex.com/


1

Viết chuyển đổi của riêng bạn.

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

0

Một phiên bản một cách đơn giản có thể được sử dụng như thế này:

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

có thể được thực hiện như thế này:

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

Chuyển đổi mọi thứ thành mọi thứ (bool, chuỗi, enum, v.v.):

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

Ví dụ về 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

Thay vì viết mã / phát minh lại của riêng bạn, hãy xem xét sử dụng 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 cũng khá hữu ích cho nhiều tình huống khác.


-2

Tôi biết đây là ngày, nhưng, bạn không cần phải thực hiện lại bất cứ điều gì.

Những gì tôi đã làm là phủ nhận giá trị trên tài sản như thế này:

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

Và nó hoạt động tốt!

Tui bỏ lỡ điều gì vậy?


7
Bạn nghĩ rằng đây là một giải pháp dễ dàng hơn và đối với một thuộc tính duy nhất, đây có thể là trường hợp (nó không thể tái sử dụng cho nhiều thuộc tính, bạn phải triển khai nó cho mọi thuộc tính). Tôi cảm thấy đây là vị trí sai cho việc triển khai, vì nó không liên quan gì đến viewmodel / codeBehind và mọi thứ với chế độ xem.
Mike Fuchs
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.