Я использую BooleanToVisibilityConverter
в WPF для привязки свойства Visibility
элемента управления к Boolean
. Это отлично работает, но я бы хотел, чтобы один из элементов управления скрывался, если логическое значение true
, и покажите, является ли оно false
.Как инвертировать BooleanToVisibilityConverter?
ответ
Внедрите свою собственную реализацию IValueConverter. Реализация образца на
http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx
В вашем методе Преобразовать иметь его возвращают значения, которые вы хотите вместо значения по умолчанию.
Напишите ваш собственный конвертер.
public class ReverseBooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// your converter code here
}
}
Существует также проект 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>
WPF-конвертеры теперь включают в себя BooleanToVisibilityConverter, который можно отменить. – vinod
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>
В 'else if (value is bool?)' Part, ReSharper сообщает мне: «Expression всегда false». Кроме того, часть 'if (flag)' может быть переписана более сжато как «флаг возврата»? Visibility.Visible: Visibility.Collapsed; '. –
Возможно, мне что-то не хватает, но разве вам не нужно отрицательное свойство? http://stackoverflow.com/questions/534575/how-do-i-invert-booleantovisibilityconverter/11800656#11800656 – OscarRyz
'var nullable = (bool?) значение; flag = nullable.GetValueOrDefault(); 'можно сделать намного короче и просто:' flag = (bool?) значение ?? false; ' – ANeves
Написать свой лучший решение на данный момент. Вот пример конвертера, который может работать как в обычном, так и в обратном порядке. Если у вас есть проблемы с этим, просто спросите.
[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», где sourcode или значение для объекта IsRunning? –
IsRunning - это свойство на моей модели. Контекст этого кода длинный, но, тем не менее, мне нужно, чтобы что-то скрывалось, когда я выполнял некоторые вычисления и другие вещи, которые не были скрыты. Я создал этот конвертер, чтобы сделать это, поэтому мне не нужно было бы иметь несколько свойств на моей модели viewmodel. –
Вы можете сделать его заменой для нормального 'BooleanToVisibilityConverter', проверив параметр для null:' Направление параметра = Parameter.Normal; if (parameter! = Null) \t direction = (Параметр) Enum.Parse (параметр typeof (Parameter), (string)); ' – JCH2k
Я просто сделал сообщение по этому вопросу. Я использовал ту же идею, что и Майкл Холиос. Только, я использовал «Свойства» вместо использования «параметра объекта».
Binding Visibility to a bool value in WPF
Использование свойств делает его более удобным для чтения, на мой взгляд.
<local:BoolToVisibleOrHidden x:Key="BoolToVisConverter" Collapse="True" Reverse="True" />
Просто последующий комментарий к моему собственному комментарию. Если вы используете «Свойства», вам нужно создать отдельный объект, если вы хотите создать для конвертеров, то есть «Обратный», а другой нет. Если вы используете параметры, вы можете использовать один объект для нескольких элементов, но это может сбивать с толку, если вы не обращаете внимания. Таким образом, для обоих есть плюсы и минусы. – Rhyous
Я нашел это очень полезным при реализации преобразователей Boolean to Colors. Спасибо – Federinik
Вместо переворачивая, вы можете достичь той же цели с помощью общего 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
.
Возможно, мне что-то не хватает, но вам не нужно просто отказаться от собственности? http://stackoverflow.com/questions/534575/how-do-i-invert-booleantovisibilityconverter/11800656#11800656 – OscarRyz
@OscarRyz: С более сложными пользовательскими интерфейсами, которые начинают добавлять много действительно раздражающего беспорядка в модели просмотра, а не чтобы упомянуть другое свойство, которое вы теоретически должны выполнить для модульного тестирования, чтобы поддерживать покрытие кода. Для просмотра моделей не нужно, чтобы * * * близко к деталям реализации представления, иначе вы могли бы просто иметь свойства «Видимость» в вашей модели представления. – Aaronaught
Я знаю, что это датировано, но вам не нужно ничего переустанавливать.
Что я сделал, чтобы свести на нет значение на имущество, как это:
<!-- 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 и все с представлением. –
Простой один способ вариант, который может быть использован, как это:
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();
}
}
Или реальный ленивый укомплектовывает путь, просто использовать то, что есть уже и переверните его:
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;
}
}
Это я написал и много использую. Он использует булево значение конвертер, который указывает, является ли или нет, чтобы инвертировать значение, а затем использует 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
Еще один способ 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>
Если вам не нравится писать пользовательский конвертер, вы можете использовать данные триггеры для решения этой проблемы:
<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>
Я искал более общий ответ, но не смог найти его. Я написал конвертер, который мог бы помочь другим.
Он основан на том, что мы должны различать шесть различных случаев:
- Правда 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'}"
Я думаю, что параметры легко запомнить.
Надеюсь, это поможет кому-то.
Вы можете использовать QuickConverter.
С QuickConverter вы можете написать конвертер логики встроенный с BindingExpression
Вот перевернутая BooleanToVisibility преобразователь:
Visibility="{qc:Binding '!$P ? Visibility.Visible : Visibility.Collapsed', P={Binding Example}}"
Вы можете добавить QuickConverter через NuGet. Посмотрите документацию по настройке. Ссылка: https://quickconverter.codeplex.com/
Примечание: в качестве бета-версии 4 - Silverlight не включает BooleanToVisibility - так что вам нужно в любом случае –
реализовать его самостоятельно Добавлен голосовой пользовательский предложение, чтобы получить инвертированный поддержали http://visualstudio.uservoice.com/ Форумы/121579-visual-studio-2015/предложения/11083446-booleantovisibilityconverter-should-allow-inverted – Thraka