Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What executes first: ToggleButton.IsChecked binding update, or Command binding?

Tags:

c#

mvvm

wpf

First - a disclaimer:

If you're reading this because you want to use both a binding for IsChecked and a RelayCommand to change things, you probably are doing it wrong. You should be working off of the IsChecked binding's Set() call.

The question:

I have a ToggleButton in which there's both a binding for IsChecked and for a Command:

<ToggleButton IsChecked="{Binding BooleanBackedProperty}" 
         Command="{Binding SomeCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
         CommandParameter="{Binding}" />

Yes - I know, tsk tsk. Couldn't be helped.

When the user clicks the ToggleButton, which these two is going to fire first? Is the Command going to be executed, or is the IsChecked binding going to update the bound property? Or - is this actually similar to the post on social in which it creates a race condition?

like image 877
Lynn Crumbling Avatar asked Jun 05 '15 20:06

Lynn Crumbling


1 Answers

IsChecked will have a valid value at the command run time.

ToggleButton overrides OnClick from ButtonBase like this:

    protected override void OnClick()
    {
        OnToggle();
        base.OnClick();
    }

OnToggle is the method that updates IsChecked:

    protected internal virtual void OnToggle()
    {
        // If IsChecked == true && IsThreeState == true   --->  IsChecked = null
        // If IsChecked == true && IsThreeState == false  --->  IsChecked = false
        // If IsChecked == false                          --->  IsChecked = true
        // If IsChecked == null                           --->  IsChecked = false
        bool? isChecked;
        if (IsChecked == true)
            isChecked = IsThreeState ? (bool?)null : (bool?)false;
        else // false or null
            isChecked = IsChecked.HasValue; // HasValue returns true if IsChecked==false
        SetCurrentValueInternal(IsCheckedProperty, isChecked);
    }

And the base OnClick fires the command:

    protected virtual void OnClick()
    {
        RoutedEventArgs newEvent = new RoutedEventArgs(ButtonBase.ClickEvent, this);
        RaiseEvent(newEvent);

        MS.Internal.Commands.CommandHelpers.ExecuteCommandSource(this);
    }

Source: MSDN Reference Source

So the value should be valid by the time the command runs.

like image 163
BradleyDotNET Avatar answered Nov 02 '22 17:11

BradleyDotNET