Як інвертувати BooleanToVisibilityConverter?


143

Я використовую BooleanToVisibilityConverterв WPF, щоб прив'язати Visibilityвластивість елемента керування до Boolean. Це прекрасно працює, але я хотів би, щоб один із елементів керування приховав булевий характер true, і показати, чи є false.


зауважте: станом на бета-версію 4 - Silverlight не включає BooleanToVisibility - так що вам потрібно буде все-таки реалізувати її самостійно
Simon_Weaver

Додано голосову пропозицію користувача, щоб отримати інвертований підтримуваний visualstudio.uservoice.com/forums/121579-visual-studio-2015/…
Thraka

Не можу повірити, що вони не реалізували деякі параметри перетворювача для таких дій.
Каміль

Відповіді:



250

Замість інвертування ви можете досягти тієї самої мети, використовуючи загальну 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);
    }
}

Далі, підклас , де Tзнаходиться Visibility:

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

Нарешті, ось як ви могли використовувати BooleanToVisibilityConverterвище в XAML і налаштувати його, наприклад, на використання Collapsedдля істинних та Visibleнеправдивих:

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

Ця інверсія корисна, коли потрібно прив’язатись до булевого властивості, названого IsHiddenна противагу IsVisible.


Я можу чогось бракувати, але чи не потрібно вам просто заперечувану властивість? stackoverflow.com/questions/534575 / ...
OscarRyz

9
@OscarRyz: Завдяки більш складним інтерфейсам, що починає додавати багато дійсно дратівливих скупчень моделям перегляду, не кажучи вже про інше властивість, яку ви теоретично доводиться проводити для тестування, щоб зберегти покриття коду. Подивитися моделі не повинні отримати , що близько до деталі реалізації думку, в іншому випадку ви можете також просто Visibilityвластивість в моделі уявлення.
Aaronaught

Це так просто, але значно корисно. Дякую @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;
    }
}

а потім передайте істинну або помилкову як 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;.
Данило Барген

1
Я можу чогось бракувати, але чи не потрібно вам просто заперечувану властивість? stackoverflow.com/questions/534575 / ...
OscarRyz

1
var nullable = (bool?)value; flag = nullable.GetValueOrDefault();можна зробити набагато коротше і простіше:flag = (bool?)value ?? false;
ANeves,

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 "Прив'язування IsRunning", де знаходиться вихідний код або значення для об'єкта "IsRunning"?
WhatUP

IsRunning - це власність на моїй оглядовій моделі. Контекст цього коду довгий, але короткий, що мені потрібно було щось приховати, коли я виконував деякі обчислення та інші речі, не приховані. Я створив цей перетворювач, щоб зробити його таким, що мені не доведеться мати декілька властивостей у своїй моделі перегляду.
Майкл Холіос

2
Ви можете зробити його заміною для нормальної BooleanToVisibilityConverter, перевіривши параметр null:Parameter direction = Parameter.Normal; if (parameter != null) direction = (Parameter)Enum.Parse(typeof(Parameter), (string)parameter);
JCH2k

20

Також існує проект WPF Converters на Codeplex. У їхній документації вони кажуть, що ви можете використовувати їх 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

Ще один спосіб прив’язати булеве значення 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>

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

Я щойно зробив пост з цього питання. Я використовував подібну ідею, як це робив Майкл Голіос. Тільки я використовував Властивості замість "параметра об'єкта".

Прив'язка видимості до значення bool у WPF за

допомогою властивостей робить його більш зрозумілим, на мою думку.

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

Просто продовження мого власного коментаря. Якщо ви використовуєте Властивості, вам потрібно створити окремий об'єкт, якщо ви хочете створити перетворювачі, той, який є зворотним, а другий - ні. Якщо ви використовуєте параметри, ви можете використовувати один об’єкт для декількох елементів, але це може бути заплутано, якщо ви не звернете уваги. Тож є і плюси і мінуси для обох.
Rhyous

Я вважаю це дуже корисним у здійсненні перетворювачів булів у кольори. Дякую
Федериник

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

Ви можете додати QuickConverter через NuGet. Подивіться документацію для налаштування. Посилання: 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

Перетворити все на все (bool, string, enum тощо):

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 і всім із видом.
Майк Фукс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.