451

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

16 Answers 16

581

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
}
Sign up to request clarification or add additional context in comments.

26 Comments

There are a few things I have to consider here, that will likely make me pick @Paul's answer over this one. I am by myself when coding (for now), so I need to go with a solution that "I" will remember, which I will use over and over. I also feel that the less wordy something is the better, and creating an inverse property is very explicit, making it easy for me to remember, as well as future dev's ( I Hope, I Hope ), to be able to quickly see what I was doing, as well as making it easier for them to throw me under the proverbial bus.
By your own arguments, IMHO the converter solution is better in the long term : you only have to write the converter once, and after that you can reuse it over and over. If you go for the new property, you will have to rewrite it in every class that needs it...
I'm using the same approach... but it makes panda saaad... =(
Compared to !, that’s some long-winded code... People go to insane amounts of effort to separate what they feel is "code" from those poor designers. Extra extra painful when I’m both the coder and the designer.
many people including myself would consider this a prime example of over-engineering. I suggest using a inverted property as in Paul Alexander post below.
|
111

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.

10 Comments

I just solved the same problem using this approach and I agree that not only is it more elegant, but much more maintainable than using a Converter.
I would disagree that this approach is better than the value converter. It also produces more code if you need several NotProperty instances.
MVVM isn't about not writing code, it's about solving problems declaratively. To that end, the converter is the correct solution.
The problem with this solution is that if you have 100 objects, you would have to add an IsNotReadOnly property to all 100 objects. That property would have to be a DependencyProperty. That adds about 10 lines of code to all 100 objects or 1000 lines of code. The Converter is 20 lines of code. 1000 lines or 20 lines. Which would you choose?
There is a common saying for this: do it once, do it twice, and then automate. In doubt, I would use this answer the first time it's needed in a project, and then if things grow, I'd use the accepted answer. But having the converter snippet pre-made might make it way less difficult to use.
|
96

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

3 Comments

Although QuickConverter is more powerful, I find the CalcBinding mode readable - usable.
This is a great tool. I wish it existed 5 years ago!
Brilliant tool, but falls over in styles. <Setter.Value><cb:Binding Path="!IsReadOnly" /></Setter.Value> gets a 'Binding' is not valid for Setter.Value' compile time error
23

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.

1 Comment

When giving a -1 to someone, it would be nice to explain why.
18

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

2 Comments

Downside is that you'd have to change all code that compared it with / assigned it to other bool Type Expressions / Variables even not referencing the inverse value. I would instead add a "Not" Extension Method to the Boolean Struct.
Doh! Never mind. Forgot had to be Property vs. Method for Binding. My "Downside" statement still applies. Btw, the 'Boolean` "Not" Extension Method is still useful for avoiding the "!" Operator which is easily missed when it (as is often the case) is embedded next to chars that look like it (i.e. one/more "("'s and "l"'s and "I"'s).
13

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

1 Comment

Great answer. One thing to add, using this you better rise the PropertyChanged event for IsNotReadOnly in the setter for the property IsReadOnly. With this you will make sure the UI gets updated correctly.
12

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
}

Comments

12

💡 .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").

Comments

4

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.

Comments

2

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

1 Comment

Seems pretty much the same than the converter approach. Format and Parse events in WinForms bindings are roughly equivalent of the WPF converter.
2

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

1 Comment

Not being a full property and lacking an "OnPropertyChanged" this won't work. 1st or 2nd answers is what I'm using, depending on the case. Unless you're using a framework like Prism where the frameowkr knows when to update "referred" properties. Then it's a toss between using something like what you suggested (but with full property), and answer 1
1

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

Comments

1

in .net Maui and using the CommunityToolkit.MVVM, we can simply do as follows:

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(IsNotBusy))]
bool isBusy;

public bool IsNotBusy => !IsBusy;

that way, whenever IsBusy is changed, IsNotBusy will be changed and notified as well.

Comments

0

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;

Comments

0

Similar to jevansio's answer, implemented a class called BindableBool with IsTrue and IsFalse properties that I can bind IsVisible of both alternate components to.

Github: https://github.com/balintn22/BindableBool

Nuget: YA.BindableBool

Comments

0

After writeing too many BooleanThisConverter and BooleanThatConverters, I finally wrote the following that made life much easier for me:

public class BooleanIffConverter: IValueConverter
{
    public object TrueValue { get; set; }
    public object FalseValue { get; set; }
    public bool NullValue { get; set; } = false;

    /// <inheritdoc />
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
        (bool) (value ?? this.NullValue) ? this.TrueValue : this.FalseValue;

    /// <inheritdoc />
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
        throw new NotSupportedException();
}
    }

Now I can use it for all sort of boolean to brush, double, visiblity, ... conversions. Specifically, for inverting a bool value:

<converters:BooleanIffConverter
    x:Key="BoolInverter"
    TrueValue="False"
    FalseValue="True" />

By default, it treats nulls as false. Set NullValue to "True" if you need the opposite.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.