2009-02-10 2 views
112

Я использую BooleanToVisibilityConverter в WPF для привязки свойства Visibility элемента управления к Boolean. Это отлично работает, но я бы хотел, чтобы один из элементов управления скрывался, если логическое значение true, и покажите, является ли оно false.Как инвертировать BooleanToVisibilityConverter?

+0

Примечание: в качестве бета-версии 4 - Silverlight не включает BooleanToVisibility - так что вам нужно в любом случае –

+0

реализовать его самостоятельно Добавлен голосовой пользовательский предложение, чтобы получить инвертированный поддержали http://visualstudio.uservoice.com/ Форумы/121579-visual-studio-2015/предложения/11083446-booleantovisibilityconverter-should-allow-inverted – Thraka

ответ

1

Напишите ваш собственный конвертер.

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

Существует также проект WPF Converters на Codeplex. В своей документации они говорят, что вы можете использовать их MapConverter для преобразования из видимости перечисления в 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

47
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?)' Part, ReSharper сообщает мне: «Expression всегда false». Кроме того, часть 'if (flag)' может быть переписана более сжато как «флаг возврата»? Visibility.Visible: Visibility.Collapsed; '. –

+1

Возможно, мне что-то не хватает, но разве вам не нужно отрицательное свойство? http://stackoverflow.com/questions/534575/how-do-i-invert-booleantovisibilityconverter/11800656#11800656 – OscarRyz

+1

'var nullable = (bool?) значение; flag = nullable.GetValueOrDefault(); 'можно сделать намного короче и просто:' flag = (bool?) значение ?? false; ' – ANeves

40

Написать свой лучший решение на данный момент. Вот пример конвертера, который может работать как в обычном, так и в обратном порядке. Если у вас есть проблемы с этим, просто спросите.

[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», где sourcode или значение для объекта IsRunning? –

+0

IsRunning - это свойство на моей модели. Контекст этого кода длинный, но, тем не менее, мне нужно, чтобы что-то скрывалось, когда я выполнял некоторые вычисления и другие вещи, которые не были скрыты. Я создал этот конвертер, чтобы сделать это, поэтому мне не нужно было бы иметь несколько свойств на моей модели viewmodel. –

+1

Вы можете сделать его заменой для нормального 'BooleanToVisibilityConverter', проверив параметр для null:' Направление параметра = Parameter.Normal; if (parameter! = Null) \t direction = (Параметр) Enum.Parse (параметр typeof (Parameter), (string)); ' – JCH2k

3

Я просто сделал сообщение по этому вопросу. Я использовал ту же идею, что и Майкл Холиос. Только, я использовал «Свойства» вместо использования «параметра объекта».

Binding Visibility to a bool value in WPF

Использование свойств делает его более удобным для чтения, на мой взгляд.

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

Просто последующий комментарий к моему собственному комментарию. Если вы используете «Свойства», вам нужно создать отдельный объект, если вы хотите создать для конвертеров, то есть «Обратный», а другой нет. Если вы используете параметры, вы можете использовать один объект для нескольких элементов, но это может сбивать с толку, если вы не обращаете внимания. Таким образом, для обоих есть плюсы и минусы. – Rhyous

+0

Я нашел это очень полезным при реализации преобразователей Boolean to Colors. Спасибо – Federinik

208

Вместо переворачивая, вы можете достичь той же цели с помощью общего 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.

+0

Возможно, мне что-то не хватает, но вам не нужно просто отказаться от собственности? http://stackoverflow.com/questions/534575/how-do-i-invert-booleantovisibilityconverter/11800656#11800656 – OscarRyz

+7

@OscarRyz: С более сложными пользовательскими интерфейсами, которые начинают добавлять много действительно раздражающего беспорядка в модели просмотра, а не чтобы упомянуть другое свойство, которое вы теоретически должны выполнить для модульного тестирования, чтобы поддерживать покрытие кода. Для просмотра моделей не нужно, чтобы * * * близко к деталям реализации представления, иначе вы могли бы просто иметь свойства «Видимость» в вашей модели представления. – Aaronaught

-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 и все с представлением. –

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

Или реальный ленивый укомплектовывает путь, просто использовать то, что есть уже и переверните его:

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

Еще один способ Bind 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> 
2

Если вам не нравится писать пользовательский конвертер, вы можете использовать данные триггеры для решения этой проблемы:

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

Я искал более общий ответ, но не смог найти его. Я написал конвертер, который мог бы помочь другим.

Он основан на том, что мы должны различать шесть различных случаев:

  • Правда 2 Видимый, Ложные 2 Hidden
  • Правда 2 Видимый, Ложные 2 Свернутые
  • Правда 2 Hidden, Ложные 2 Видна
  • Правда 2 Свернутые, Ложные 2 Видимый
  • Правда 2 Hidden, Ложные 2 Свернутые
  • Правда 2 Свернутые, Ложные 2 Hidden

Вот моя реализация в течение первых 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'}" 

Я думаю, что параметры легко запомнить.

Надеюсь, это поможет кому-то.

1

Вы можете использовать QuickConverter.

С QuickConverter вы можете написать конвертер логики встроенный с BindingExpression

Вот перевернутая BooleanToVisibility преобразователь:

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

Вы можете добавить QuickConverter через NuGet. Посмотрите документацию по настройке. Ссылка: https://quickconverter.codeplex.com/