How to bind inverse boolean properties in WPF?

Wpf.Net 3.5Styles

Wpf Problem Overview


What I have is an object that has an IsReadOnly property. If this property is true, I would like to set the IsEnabled property on a Button, ( for example ), to false.

I would like to believe that I can do it as easily as IsEnabled="{Binding Path=!IsReadOnly}" but that doesn't fly with WPF.

Am I relegated to having to go through all of the style settings? Just seems too wordy for something as simple as setting one bool to the inverse of another 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>

Wpf Solutions


Solution 1 - Wpf

You can use a ValueConverter that inverts a bool property for you.

XAML:

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

Converter:

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

Solution 2 - Wpf

Have you considered an IsNotReadOnly property? If the object being bound is a ViewModel in a MVVM domain, then the additional property makes perfect sense. If it's a direct Entity model, you might consider composition and presenting a specialized ViewModel of your entity to the form.

Solution 3 - Wpf

With standard bindings you need to use converters that look a little windy. So, I recommend you to look at my project CalcBinding, which was developed specifically to resolve this problem and some others. With advanced binding you can write expressions with many source properties directly in xaml. Say, you can write something like:

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

or

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

or

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

or

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

where A, B, C, IsChecked - properties of viewModel and it will work properly

Solution 4 - Wpf

I would recommend using https://github.com/JohannesMoersch/QuickConverter

Inverting a boolean is then as simple as: <Button IsEnabled="{qc:Binding '!$P', P={Binding IsReadOnly}}" />

That speeds the time normally needed to write converters.

Solution 5 - Wpf

I wanted my XAML to remain as elegant as possible so I created a class to wrap the bool which resides in one of my shared libraries, the implicit operators allow the class to be used as a bool in code-behind seamlessly

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

}

The only changes needed to your project are to make the property you want to invert return this instead of bool

    public InvertableBool IsActive 
    { 
        get 
        { 
            return true; 
        } 
    }

And in the XAML postfix the binding with either Value or Invert

IsEnabled="{Binding IsActive.Value}"

IsEnabled="{Binding IsActive.Invert}"

Solution 6 - Wpf

This one also works for nullable bools.

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

Solution 7 - Wpf

Add one more property in your view model, which will return reverse value. And bind that to button. Like;

in view model:

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

in xaml:

IsEnabled="{Binding IsNotReadOnly"}

Solution 8 - Wpf

.Net Core Solution

Handles null situation and does not throw an exception, but returns true if no value is presented; otherwise takes the inputted Boolean and reverses it.

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 I like to put all my converter statics in the app.xaml file so I don't have to redeclare them throughout the windows/pages/controls of the project.

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

To be clear converters: is the namespace to the actual class implementation ( xmlns:converters="clr-namespace:ProvingGround.Converters").

Solution 9 - Wpf

I had an inversion problem, but a neat solution.

Motivation was that the XAML designer would show an empty control e.g. when there was no datacontext / no MyValues (itemssource).

Initial code: hide control when MyValues is empty. Improved code: show control when MyValues is NOT null or empty.

Ofcourse the problem is how to express '1 or more items', which is the opposite of 0 items.

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

I solved it by adding:

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

Ergo setting the default for the binding. Ofcourse this doesn't work for all kinds of inverse problems, but helped me out with clean code.

Solution 10 - Wpf

Don't know if this is relevant to XAML, but in my simple Windows app I created the binding manually and added a Format event handler.

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

Solution 11 - Wpf

Following @Paul's answer, I wrote the following in the ViewModel:

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

I hope having a snippet here will help someone, probably newbie as I am.
And if there's a mistake, please let me know!

BTW, I also agree with @heltonbiker comment - it's definitely the correct approach only if you don't have to use it more than 3 times...

Solution 12 - Wpf

I did something very similar. I created my property behind the scenes that enabled the selection of a combobox ONLY if it had finished searching for data. When my window first appears, it launches an async loaded command but I do not want the user to click on the combobox while it is still loading data (would be empty, then would be populated). So by default the property is false so I return the inverse in the getter. Then when I'm searching I set the property to true and back to false when complete.

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

Then for the combobox I can bind it directly to the IsSearching:

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

Solution 13 - Wpf

I use a similar approach like @Ofaim

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

public bool EnableSaveButton => !jobSaved;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRussView Question on Stackoverflow
Solution 1 - WpfChris NicolView Answer on Stackoverflow
Solution 2 - WpfPaul AlexanderView Answer on Stackoverflow
Solution 3 - WpfAlex141View Answer on Stackoverflow
Solution 4 - WpfNoxxysView Answer on Stackoverflow
Solution 5 - WpfjevansioView Answer on Stackoverflow
Solution 6 - WpfAndreasView Answer on Stackoverflow
Solution 7 - WpfMMMView Answer on Stackoverflow
Solution 8 - WpfΩmegaManView Answer on Stackoverflow
Solution 9 - WpfEricGView Answer on Stackoverflow
Solution 10 - WpfSimon DobsonView Answer on Stackoverflow
Solution 11 - WpfOfaimView Answer on Stackoverflow
Solution 12 - WpfGregNView Answer on Stackoverflow
Solution 13 - WpfsoulflymanView Answer on Stackoverflow