如何绑定逆布尔属性在WPF?

我拥有的是一个具有IsReadOnly属性的对象。如果此属性为true,我想将Button(例如)上的IsEnabled属性设置为false。

我愿意相信我可以像IsEnabled="{Binding Path=!IsReadOnly}"一样轻松地做到这一点,但这并不与WPF一起飞行。

我是否不得不经历所有的样式设置?对于将一个bool值设置为另一个bool值的倒数这样简单的事情来说,似乎太啰嗦了。

<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsReadOnly}" Value="True">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsReadOnly}" Value="False">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
249986 次浏览

你可以使用ValueConverter来反转bool属性。

XAML:

IsEnabled="{Binding Path=IsReadOnly, Converter={StaticResource InverseBooleanConverter}}"

转换器:

[ValueConversion(typeof(bool), typeof(bool))]
public class InverseBooleanConverter: IValueConverter
{
#region IValueConverter Members


public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (targetType != typeof(bool))
throw new InvalidOperationException("The target must be a boolean");


return !(bool)value;
}


public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}


#endregion
}

你考虑过IsNotReadOnly属性吗?如果被绑定的对象是MVVM域中的ViewModel,那么附加属性非常有意义。如果它是一个直接的实体模型,您可能会考虑组合并将实体的专用ViewModel呈现给表单。

我建议使用https://github.com/JohannesMoersch/QuickConverter

反转一个布尔值就像这样简单: <Button IsEnabled="{qc:Binding '!$P', P={Binding IsReadOnly}}" /> < / p >

这加快了编写转换器通常所需的时间。

对于标准绑定,您需要使用看起来有点风的转换器。所以,我建议你看看我的项目CalcBinding,它是专门解决这个问题和其他一些问题而开发的。使用高级绑定,您可以直接在xaml中编写带有许多源属性的表达式。比如,你可以这样写:

<Button IsEnabled="{c:Binding Path=!IsReadOnly}" />

<Button Content="{c:Binding ElementName=grid, Path=ActualWidth+Height}"/>

<Label Content="{c:Binding A+B+C }" />

<Button Visibility="{c:Binding IsChecked, FalseToVisibility=Hidden}" />

其中A, B, C, IsChecked - viewModel的属性,它将正常工作

不知道这是否与XAML相关,但在我简单的Windows应用程序中,我手动创建了绑定,并添加了一个格式事件处理程序。

public FormMain() {
InitializeComponent();


Binding argBinding = new Binding("Enabled", uxCheckBoxArgsNull, "Checked", false, DataSourceUpdateMode.OnPropertyChanged);
argBinding.Format += new ConvertEventHandler(Binding_Format_BooleanInverse);
uxTextBoxArgs.DataBindings.Add(argBinding);
}


void Binding_Format_BooleanInverse(object sender, ConvertEventArgs e) {
bool boolValue = (bool)e.Value;
e.Value = !boolValue;
}

我希望我的XAML尽可能保持优雅,所以我创建了一个类来包装驻留在我的一个共享库中的bool类型,隐式操作符允许类在代码中无缝地用作bool类型

public class InvertableBool
{
private bool value = false;


public bool Value { get { return value; } }
public bool Invert { get { return !value; } }


public InvertableBool(bool b)
{
value = b;
}


public static implicit operator InvertableBool(bool b)
{
return new InvertableBool(b);
}


public static implicit operator bool(InvertableBool b)
{
return b.value;
}


}

你的项目需要做的唯一改变就是让你想要反转的属性返回this而不是bool

    public InvertableBool IsActive
{
get
{
return true;
}
}

在XAML中,用Value或Invert后缀绑定

IsEnabled="{Binding IsActive.Value}"


IsEnabled="{Binding IsActive.Invert}"

这个方法也适用于可为空的bool。

 [ValueConversion(typeof(bool?), typeof(bool))]
public class InverseBooleanConverter : IValueConverter
{
#region IValueConverter Members


public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType != typeof(bool?))
{
throw new InvalidOperationException("The target must be a nullable boolean");
}
bool? b = (bool?)value;
return b.HasValue && !b.Value;
}


public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return !(value as bool?);
}


#endregion
}
在视图模型中添加一个属性,它将返回反向值。 然后把它绑定到按钮上。 < / p >;

视图模型:

public bool IsNotReadOnly{get{return !IsReadOnly;}}

在xaml:

IsEnabled="{Binding IsNotReadOnly"}

我遇到了一个倒置的问题,但是有一个简洁的解决方法。

动机是XAML设计器会显示一个空控件,例如当没有数据上下文/没有MyValues (itemssource)时。

初始代码:当MyValues为空时,隐藏控件。 改进的代码:当MyValues不是null或空时显示控件

当然,问题是如何表达“1个或多个项目”,这与0个项目相反。

<ListBox ItemsSource={Binding MyValues}">
<ListBox.Style x:Uid="F404D7B2-B7D3-11E7-A5A7-97680265A416">
<Style TargetType="{x:Type ListBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding MyValues.Count}">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>

我通过添加:

<DataTrigger Binding="{Binding MyValues.Count, FallbackValue=0, TargetNullValue=0}">

因此,为绑定设置默认值。当然,这并不适用于所有类型的逆问题,但帮助我用干净的代码。

在@Paul的回答之后,我在ViewModel中写了以下内容:

public bool ShowAtView { get; set; }
public bool InvShowAtView { get { return !ShowAtView; } }
我希望在这里有一个片段能帮助到一些人,可能是像我这样的新手 如果有错误,请告诉我!< / p >

顺便说一句,我也同意@heltonbiker的评论——这绝对是正确的方法只有在,你不必使用它超过3次…

我也做过类似的事情。我在幕后创建了我的属性,使组合框只有在它完成搜索数据时才可以选择。当我的窗口第一次出现时,它启动了一个异步加载命令,但我不希望用户在它仍在加载数据时单击组合框(将是空的,然后将被填充)。默认情况下,属性为false,所以我在getter中返回逆函数。然后,当我搜索时,我将属性设置为true,完成时返回为false。

private bool _isSearching;
public bool IsSearching
{
get { return !_isSearching; }
set
{
if(_isSearching != value)
{
_isSearching = value;
OnPropertyChanged("IsSearching");
}
}
}


public CityViewModel()
{
LoadedCommand = new DelegateCommandAsync(LoadCity, LoadCanExecute);
}


private async Task LoadCity(object pArg)
{
IsSearching = true;


//**Do your searching task here**


IsSearching = false;
}


private bool LoadCanExecute(object pArg)
{
return IsSearching;
}

然后,对于组合框,我可以直接绑定到IsSearching:

<ComboBox ItemsSource="{Binding Cities}" IsEnabled="{Binding IsSearching}" DisplayMemberPath="City" />

我使用类似于@Ofaim的方法

private bool jobSaved = true;
private bool JobSaved
{
get => jobSaved;
set
{
if (value == jobSaved) return;
jobSaved = value;


OnPropertyChanged();
OnPropertyChanged("EnableSaveButton");
}
}


public bool EnableSaveButton => !jobSaved;

💡__abc0💡

处理空情况,不抛出异常,但如果没有值则返回true;否则取输入的布尔值并将其反转。

public class BooleanToReverseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> !(bool?) value ?? true;


public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> !(value as bool?);
}

Xaml

IsEnabled="{Binding IsSuccess Converter={StaticResource BooleanToReverseConverter}}"

App.Xaml我喜欢把我所有的转换器静态在app.xaml文件中,这样我就不必在整个项目的窗口/页面/控件中重新声明它们。

<Application.Resources>
<converters:BooleanToReverseConverter x:Key="BooleanToReverseConverter"/>
<local:FauxVM x:Key="VM" />
</Application.Resources>

要清楚的是,converters:是实际类实现(xmlns:converters="clr-namespace:ProvingGround.Converters")的命名空间。