如何在WPF中绑定反布尔属性?

时间:2009-06-24 16:59:54

标签: wpf .net-3.5 styles

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

我想相信我可以像IsEnabled="{Binding Path=!IsReadOnly}"一样轻松地做到这一点,但这不会与WPF一起发生。

我是否已经不得不经历所有的风格设置?对于像将一个布尔设置为另一个布尔的反转这样简单的事情,似乎太过冗长。

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

13 个答案:

答案 0 :(得分:434)

您可以使用为您反转bool属性的ValueConverter。

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
    }

答案 1 :(得分:93)

您是否考虑过IsNotReadOnly财产?如果绑定的对象是MVVM域中的ViewModel,则附加属性非常有意义。如果它是直接实体模型,您可以考虑合成并将实体的专用ViewModel呈现给表单。

答案 2 :(得分:61)

使用标准装订,您需要使用看起来有风的转换器。因此,我建议您查看我的项目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的属性,它将正常工作

古德勒克!

答案 3 :(得分:18)

我建议使用https://quickconverter.codeplex.com/

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

这可以加快编写转换器所需的时间。

答案 4 :(得分:13)

我希望我的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;
    }

}

项目所需的唯一更改是使您想要反转的属性返回而不是bool

    public InvertableBool IsActive 
    { 
        get 
        { 
            return true; 
        } 
    }

在XAML后缀中,使用Value或Invert

进行绑定
IsEnabled="{Binding IsActive.Value}"

IsEnabled="{Binding IsActive.Invert}"

答案 5 :(得分:8)

这个也适用于可空的布尔。

<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

答案 6 :(得分:2)

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

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

答案 7 :(得分:2)

? .Net Core解决方案>

处理空情况并且不引发异常,但是如果不提供任何值,则返回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文件中,因此我不必在项目的Windows /页面/控件中重新声明它们。

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

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

答案 8 :(得分:1)

在视图模型中再添加一个属性,该属性将返回反向值。 并将其绑定到按钮。 等;

在视图模型中

public bool IsNotReadOnly{get{return !IsReadOnly;}}
xaml中的

IsEnabled="{Binding IsNotReadOnly"}

答案 9 :(得分:1)

我有一个倒置问题,但是一个简洁的解决方案。

动机是XAML设计师会显示一个空控件,例如当没有datacontext / no MyValues(itemssource)时。

初始代码:MyValues为空时隐藏控件。 改进的代码:当MyValues非空或空时 show 控制。

当然问题是如何表达一个或多个项目,这与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}">

Ergo设置绑定的默认值。当然,这并不适用于所有类型的反问题,但帮助我解决了干净的代码问题。

答案 10 :(得分:1)

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

public bool ShowAtView { get; set; }
public bool InvShowAtView { get { return !ShowAtView; } }

我希望在这里有一个片段可以帮助某人,可能是我的新手 如果有错误,请告诉我!

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

答案 11 :(得分:1)

我做了一些非常相似的事情。我在幕后创建了我的属性,只有在完成搜索数据时才能选择组合框。当我的窗口第一次出现时,它会启动异步加载的命令,但我不希望用户在仍然加载数据时单击组合框(将为空,然后将填充)。因此默认情况下该属性为false,因此我在getter中返回inverse。然后,当我搜索时,我将属性设置为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" />

答案 12 :(得分:0)

我使用类似@Ofaim的方法

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

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

public bool EnableSaveButton => !jobSaved;