11

I am developing a simple exercise and want to know if there is a way to bind to the opposite of another element using only XAML. For example. I have two buttons on a form, Start and Stop perhaps for a timer. I dont want both to be enables at the same time. When the program starts, the stop button should be disabled. When the start button is clicked, it should be disabled and the stop button enabled. Then vice versa until the user quits.

I know there are better controls for exactly this, and I know it is easy to do in code. I just wanted to know if there is some sort of NOT operator in XAML that could look like this:

<Button Content="_Start" Name="btnStart"/>
<Button Content="_Stop" Name="btnStop"
        IsEnabled="{Binding ElementName=btnStart,
                    Path=Not(IsEnabled)}"/>

Or something like:

                    Path != IsEnabled}"/>

Or even something like:

                    Path=IsEnabled.Not()}"/>

I know I can bind directly to the start button, but when one is enabled so is the other, and likewise when it is disabled. See where I am comming from.

I would be even willing to entertain some sort of XAML Validation thehnique which will first check the state of the start button and force the state of the stop one to be the opposite. Or any other similar hacks or workarounds that dont require codebehind.

Thanks for any help on this.

EDITS: Remember the key point for this is NO code behind. If I have to write a single line of code behind I might as well just use the onclick event handler and a simple ?: operator. So I want only something that will work directly in XAML.

Francis Rodgers
  • 4,565
  • 8
  • 46
  • 65

2 Answers2

16

There isn't a Not operation out of the box. However, it's pretty easy to achieve this yourself using a custom converter:

public class NotConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return !(bool) value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return !(bool)value;
    }
}

Then you can specify it as a converter on your binding.

<Button Content="_Stop" Name="btnStop"
    IsEnabled="{Binding ElementName=btnStart, Converter={StaticResource NotConverter} Path=IsEnabled}"/>

And finally create a resource on your Window / Page called NotConverter:

<Window.Resources>
    <ns:NotConverter x:Key="NotConverter" />
</Window.Resources>

You can get a more information about IValueConverter from MSDN.

Then use can use this value converter anywhere you'd like. You could pull it out of the Window resources and make it a application-level resource so you don't have to specify it in every window.

vcsjones
  • 138,677
  • 31
  • 291
  • 286
  • 2
    @FrancisRodgers If want to handle the click event yourself, that's fine. But you only have to write this value converter *once*. When happens when you need to handle 17 buttons? Write the click handler for all 17, or write a value converter once? It's re-usable. – vcsjones Sep 24 '11 at 15:19
  • Ok, I do see your point. Very well taken. Thank you. I would still like to know if I can do it using validation rules and without code though. Just for fun. – Francis Rodgers Sep 24 '11 at 15:23
  • Using this method, I get the error: "The type ns:NotConverter was not found. Verify that you are not missing an assembly refrence and that all refrence assemblies have been built". How do I go about fixing this. Thanks again. – Francis Rodgers Sep 24 '11 at 16:19
  • 1
    @FrancisRodgers - Make sure to add an xmlns to your Window / Application for `ns` which is the namespace of where you put the type. For example `xmlns:ns="clr-namespace:Your.Namespace.Here"` – vcsjones Sep 24 '11 at 16:25
  • 1
    @FrancisRodgers You can learn more about XAML and namespace at http://msdn.microsoft.com/en-us/library/ms747086.aspx – vcsjones Sep 24 '11 at 16:25
3

If i know it right then you can't bind to !Property, but you can Write a IValueConverter and use it in your binding. And here it is explained in detail how you can set up an IValueConverter which returns a Negated Boolean value.

IValueConverter to negate a property

Community
  • 1
  • 1
BigL
  • 1,631
  • 1
  • 11
  • 10
  • if done without code, only in XAML, can you explain how. I know I can use code to to this but if I have to write a single line of code then I might as well do the whole thing in code as it will be easy to acheive and understand. So really what I am looking for is some advanced XAML that you wouldnt typically see every day. Even better if it is simple XAML as long as it is XAML without any code. – Francis Rodgers Sep 24 '11 at 15:14
  • At the link which i have in my answer you can read Jobi Joy's answer, he says that with an XAML Mark up Extension it is possible to make it in xaml but it is way to much work. And i think the IValueConverter option is the best because you can reuse the converter in the future, and it is very simple actually 2 lines of code in the convert and convert back methods and then you have to add a resource to your application, don't forget to add the Converters Namespace to your XAML, and then you will be able to use the converter in your bindings with converter={StatickResource convertersresourcename} – BigL Sep 24 '11 at 15:20