views:

308

answers:

1

In my WPF application I have a CheckBox whose IsChecked value is bound to a property in my viewmodel. Notice that I have commented out the actual line which sets the value in my viewmodel. It's the standard pattern:

View.xaml

<CheckBox IsChecked="{Binding Path=SomeProperty}" />

ViewModel.cs

public bool SomeProperty
{
    get { return this.mSomeProperty; }
    set
    {
        if (value != this.mSomeProperty)
        {
            //this.mSomeProperty = value;
            NotifyPropertyChanged(new PropertyChangedEventArgs("SomeProperty"));
        }
    }
}

When I click the CheckBox I expect nothing to happen, since the value of this.mSomeProperty does not get set. However the observed behavior is that the CheckBox is being checked and unchecked regardless of the value of this.mSomeProperty.

What is going on? Why isn't my binding forcing the CheckBox to show what the underlying data model is set to?

+2  A: 

Because WPF does not automatically reload from the binding source after updating the source. This is probably partly for performance reasons, but mostly to handle binding failures. For example, consider a TextBox bound to an integer property. Suppose the user types 123A. WPF wants to continue showing what the user typed so that they can correct it, rather than suddenly resetting the TextBox contents to the old value of the property.

So when you click the CheckBox, WPF assumes that it should continue to display the control state, not to re-check the bound property.

The only way I've found around this, which is not very elegant, is to raise PropertyChanged after WPF has returned from calling the property setter. This can be done using Dispatcher.BeginInvoke:

set
{
  // ...actual real setter logic...
  Action notify = () => NotifyPropertyChanged(...);
  Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, notify);
}

This could be made a bit less horrible by consolidating it into the NotifyPropertyChanged implementation so that you wouldn't have to pollute individual properties with this implementation concern. You might also be able to use NotifyOnSourceUpdated and the SourceUpdated attached event, but I haven't explored this possibility.

itowlson
A creative solution certainly, but... ugh... I hope there's a cleaner solution out there!
emddudley
Microsoft changed binding behavior in .NET 4.0 so that controls will now check the bound property after setting it. http://karlshifflett.wordpress.com/2009/05/27/wpf-4-0-data-binding-change-great-feature/
emddudley