439

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>
Tim Pohlmann
  • 4,140
  • 3
  • 32
  • 61
Russ
  • 12,312
  • 20
  • 59
  • 78

16 Answers16

568

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
    }
Chris Nicol
  • 10,256
  • 7
  • 39
  • 49
  • 9
    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. – Russ Jun 24 '09 at 18:07
  • 18
    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... – Thomas Levesque Jun 26 '09 at 08:30
  • Chris, Thomas I want you both to know that even though I picked Paul's answer as "the answer", and I don't feel it’s fair to change that pick this late in the game, I am conceding here that you were both right, and the converter has become much more useful to me, especially when using framework values where I have no control. – Russ Aug 03 '09 at 13:03
  • No problem ... just as long as you have a solution that works for you then that's all that matters. Converters are great though aren't they! – Chris Nicol Aug 04 '09 at 07:22
  • 52
    I'm using the same approach... but it makes panda saaad... =( – Massimiliano Jan 04 '10 at 21:34
  • 37
    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. – Roman Starkov Apr 14 '12 at 14:48
  • 1
    I am in the unenviable position of already having a BoolToVisibilityConverter but I now want the Visibility to be off when the bool is on. Since I don't feel like making yet another InverseBoolToVisibilityConverter, I think I'll go with the inverted property on the Model. – Tom Padilla Sep 06 '12 at 03:10
  • 4
    **Xceed.Wpf.DataGrid** includes some converters. This one, InverseBooleanConverter, is included in that assembly. I have this in a ResourceDictionary `xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid"` with this resource `` – Michael Yanni Dec 27 '12 at 16:08
  • 2
    So I'm using a MultiBinding whose converter simply ANDs together several inner boolean bindings. One of these inner boolean bindings happens to use this InverseBooleanConverter. Since the target type is now a System.Object (i.e. the MultiBinding element) instead of System.Boolean (i.e. a boolean property) then the converter fails do to the target type bool check exception. – bugged87 Feb 15 '13 at 20:46
  • I get a XamlParseException: "Provide value on 'System.Windows.Markup.StaticResourceHolder' threw an exception." -- I have the class, and I used the Binding as shown -- is there something else that needs to be done? Does the binding need to be registered somehow, or placed in a StaticResource or something? – BrainSlugs83 Jan 01 '14 at 00:40
  • 1
    Figured it out. There's probably a way to do this declaratively, but I don't know what that is. I just put this as the first line in my UserControl's constructor and all is well: `this.Resources["InverseBooleanConverter"] = new InverseBooleanConverter();` – BrainSlugs83 Jan 01 '14 at 00:44
  • 11
    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. – Christian Westman Jan 14 '14 at 12:32
  • 6
    In my opinion, the converter is a much more elegant solution than adding a property to my class every time I need to bind something in a different way. Without converters, many of my classes would be littered with properties that would be useless in my code. Also if I want to use a Boolean property for Visibility, I would need to refer to the WPF Visibility Enum in my class as well. If you want to keep your code clean, I believe that converters are the way to go. (+1) – user3308241 Mar 06 '15 at 21:39
  • 4
    I think it is over-engineering only in the respect that Microsoft should have provided this converter rather than expecting everyone to reinvent the wheel by making their own. – Epirocks Oct 17 '17 at 11:32
  • 1
    You MVVM purists are like frogs in a boiling MVVM pot! The choice should *not* be adding an inverse `Property` vs. `Converter`. It *should* be inverse `Property` vs. a "!" Operator in the `Binding` Expression or the "https://github.com/Alex141/CalcBinding" Project in Alex141's Answer below. Just like we should've *never* allowed MS to get away with Literal String Property Names in the "RaisePropertyChanged" Calls (which they finally *acceptably* resolved 5 YRS later w/ `CallerMemberName` in VS 2012)! And they *still* need compile-time option to check Property Names in View vs. ViewModel!?! – Tom Jan 18 '18 at 00:29
  • 1
    Actually, for "RaisePropertyChanged" Calls from outside the Property itself, it wasn't *acceptably* resolved until 8 YRS later (w/ `nameof` Expression in VS 2015)!?! Sigh. Re. "compile-time option to check Property Names in View vs. ViewModel": Yes, I know a lot of VM's are Bound at run-time and (although not recommended) there *could* be multiple VM's per View. I'm suggesting a compile-time *option* to *temporarily*, *declaratively* Bind to a VM for the sole purpose of doing a sanity-check on all the `Property` Names in the `Binding`s and that would be turned off prior to Build if passed. – Tom Jan 18 '18 at 00:42
  • 1
    I just searched my code base and someone already copied your code. – RayLoveless Aug 08 '18 at 21:44
  • I also use this converter and noticed that some properties e.g. IsChecked are bool? instead of bool. Before using this piece of code make sure it's actually a bool. Otherwise the exception will be thrown. – 0lli.rocks Jul 18 '19 at 13:18
  • Actually, it will be much handy to skip check for the type: ` if (targetType != typeof(bool))` in order to use this in converters chaining case. Or just in case if you need only to inverse the boolean but not necessary inside `IsChecked` kind of attribute. – Arsen Khachaturyan Dec 03 '20 at 15:33
  • Two boolean flags will be more clear than all this code lol – MeTitus May 21 '21 at 11:00
  • Instead of checking the "targetType", check the type of "value". I ran into a case where the "targetType" was string, but the "value" object was System.Boolean, which is what was expected. – Scott Siddall Dec 15 '21 at 12:51
  • You should return System.Windows.DependencyProperty.UnsetValue if the value is not a bool instead of throwing an exception. – CBFT Apr 27 '22 at 20:55
  • I have a set of functions or converters that I have packed in a dll, I reference it in all of my projects. Thus it is quite easy and widely applicable for me to use converters over tweaks that will solve one scenario but not all of them. – TheCoder Jun 06 '22 at 07:21
  • 1
    @Massimiliano, I realise it's been centuries since your comment and last you gazed upon this question dinosaurs roamed the Earth but if you could search any ancient scrolls you may have, I'd be curious to know what panda you are referring to? I know exhentai didn't exist while we still lived in caves. – notarobot Apr 01 '23 at 17:22
  • @notarobot just search for “sad panda South Park” on YouTube – Massimiliano Apr 02 '23 at 21:33
110

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.

d219
  • 2,707
  • 5
  • 31
  • 36
Paul Alexander
  • 31,970
  • 14
  • 96
  • 151
  • 5
    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. – alimbada Sep 24 '10 at 16:43
  • It also has less performance implications, which is especially important in things like the Windows Phone. – Joel Shea Apr 05 '11 at 08:49
  • 4
    IMO, this is the preferred solution. MVVM is the way to go. While a converter does the job, if you can avoid the code in the first place... +1 from me. – Scott Marlowe Apr 15 '11 at 18:53
  • 28
    I would disagree that this approach is better than the value converter. It also produces more code if you need several NotProperty instances. – Thiru Jun 26 '12 at 00:31
  • 32
    MVVM isn't about not writing code, it's about solving problems declaratively. To that end, the converter *is* the correct solution. – Jeff Dec 31 '12 at 16:41
  • 16
    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? – Rhyous May 13 '14 at 20:59
  • 13
    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. – heltonbiker Feb 09 '15 at 17:54
  • 2
    I tend to use the same approach in general, but in this case I don't like the fact that every time I have to notify a change to IsReadOnly property I need to remeber to notify IsNotReadOnly property too, otherwise I will have a not aligned interface. Logically they are the same property, and I don't like to have two different representations of it, eventually not aligned. – Daniele Armanasco Apr 19 '19 at 09:57
  • @DanieleArmanasco I agree, but as a way to avoid having to remember to set both, why not set the negative bool property from the setter of the positive bool property? Then, the negative bool property is never set directly. – Jamie Dec 23 '20 at 21:21
  • This is not the right answer simply because one of the main philosophies of MVVM is to make the View Model completely independent of the View. If the View Model has a property called `CanOpen`, that is a reflection of a model's property contained in the business logic that represents some sort of permission the user has (as an example), then creating an extra `CannotOpenReadOnly` property just to accomodate the view, is an anti-pattern. – AsPas Aug 20 '21 at 13:15
91

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

Neil B
  • 2,096
  • 1
  • 12
  • 23
Alex141
  • 1,163
  • 8
  • 10
22

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.

PandaWood
  • 8,086
  • 9
  • 49
  • 54
Noxxys
  • 879
  • 1
  • 9
  • 19
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}"
jevansio
  • 181
  • 1
  • 2
  • 2
    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`. – Tom Jan 18 '18 at 00:16
  • 1
    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). – Tom Jan 18 '18 at 01:54
12

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"}
MMM
  • 121
  • 1
  • 6
  • 2
    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. – Muhannad Sep 06 '18 at 21:24
  • This should be the accepted answer as it is the simplest. – gabnaim Feb 05 '20 at 16:13
11

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
}
Andreas
  • 3,843
  • 3
  • 40
  • 53
10

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

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
3

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.

EricG
  • 3,788
  • 1
  • 23
  • 34
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;
}
Simon Dobson
  • 101
  • 1
  • 2
  • 1
    Seems pretty much the same than the converter approach. `Format` and `Parse` events in WinForms bindings are roughly equivalent of the WPF converter. – Alejandro Jan 21 '16 at 13:15
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...

Ofaim
  • 41
  • 3
  • 2
    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 – Oyiwai May 15 '19 at 16:42
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" />
GregN
  • 142
  • 1
  • 13
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;
soulflyman
  • 500
  • 1
  • 5
  • 16
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

balintn
  • 988
  • 1
  • 9
  • 19
0

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.

Muhammad Assar
  • 659
  • 7
  • 16
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.

saastn
  • 5,717
  • 8
  • 47
  • 78