Change a Dependency Property in the setter of a bound property

ItemSelectionQuite a confusing title, but here is an example where this can be interesting (Note: I’m mot using my ViewModel library to keep this simpler).

Let’s say we have a list of values and the user can select one of them. Under special conditions (here in case that a checkbox is checked) we don’t want the user to change the selected item. It could look like in the screenshot on the right.

The following code would be logical to reach a behavior like that:

Foo.cs:

public sealed class Foo : INotifyPropertyChanged
{
    private string selectedItem;
    private bool denySelectionChange;

    public string SelectedItem
    {
        get
        {
            return this.selectedItem;
        }
        set
        {
            if (!String.Equals(this.selectedItem, value))
            {
                if (!this.DenySelectionChange)
                    this.selectedItem = value;

                this.OnPropertyChanged("SelectedItem");
            }
        }
    }
    public bool DenySelectionChange
    {
        get
        {
            return this.denySelectionChange;
        }
        set
        {
            if (this.denySelectionChange != value)
            {
                this.denySelectionChange = value;
                this.OnPropertyChanged("DenySelectionChange");
            }
        }
    }
    public ReadOnlyObservableCollection<string> Items
    {
        get;
        private set;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public Foo(ObservableCollection<string> items)
    {
        this.Items = new ReadOnlyObservableCollection<string>(items);
    }

    private void OnPropertyChanged(string p)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(p));
    }
}

Window1.xaml:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <DockPanel>
        <CheckBox Content="Deny Selection change"
                  IsChecked="{Binding Path=DenySelectionChange}"
                  DockPanel.Dock="Bottom" />

        <ListBox ItemsSource="{Binding Path=Items}"
                 SelectedItem="{Binding Path=SelectedItem}" />
    </DockPanel>
</Window>

Window1.xaml.cs (only in order to fill the listbox):

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        Foo foo = new Foo(new ObservableCollection<string> { "Item 1", "Item 2", "Item 3", "Item 4" });
        this.DataContext = foo;
    }
}

However, you will still be able to change the selected item when the checkbox is checked.

I didn’t find a reason for that. It seems the data binding engine of the WPF doesn’t like it when you change a property while its informing the bound properties about a previous change.

But I have a solution 😉

It’s quite easy: Just change the property back (= raise PropertyChanged) after we have left the Setter.

How to achieve that?

That’s also quite easy: Use Dispatcher.BeginInvoke:

public string SelectedItem
{
    get //...
    set
    {
        if (!String.Equals(this.selectedItem, value))
        {
            if (!this.DenySelectionChange)
                this.selectedItem = value;

            Action action = () => this.OnPropertyChanged("SelectedItem");
            Dispatcher.CurrentDispatcher.BeginInvoke(action);
        }
    }
}

It should work now.

DotNetKicks Image
Advertisements
Posted in WPF. Tags: , , , . Comments Off on Change a Dependency Property in the setter of a bound property