Sunday, September 4

WPF Binding Mode OneTime

I've been using WPF for the past 5 year and never found a reason to use Binding Mode of OneTime.
As everyone I've read the documentation that state:
Updates the binding target when the application starts or when the data context changes...
but I never found a real use for it.

Until today!
The use case was an editor control for selecting activity from a process. The data is really simple: we have a list of processes and each process has list of activities. The actual value I was interested in is the activity but it's not so user friendly to show the user lists of thousands of items so I break it into a first combo box of process and then combo box of activities in the selected process.

The first XAML look like this:

            <ComboBox
                x:Name="ProcessBox"
                SelectedValue="{Binding Path=Value.Process}"
                DisplayMemberPath="Name"
                IsEditable="True" />

            <ComboBox
                SelectedValue="{Binding Value}"
                ItemsSource="{Binding Mode=OneWay, ElementName=ProcessBox, Path=SelectedValue.Activities}"
                DisplayMemberPath="DisplayName"
                IsEditable="True" />

As you can see the first combo box (ProcessBox) is bound to the actual value's (the activity) process. This is important when we present this editor to an already selected activity and we want to show the user the process the activity belong to.
The second combo take it's ItemsSource from the first combo box and it's SelectedValue is bound to the actual value in the ViewModel.

This works pretty good, except when the user try to find the activity in the second combo box they often use the auto complete feature of the combo box and it often result in the bound Value property turn into null when the user enter name that does not exists in the list.

This is the moment the binding works against us and it's manifest in the ProcessBox combo turn empty. This is really frustrating to the user and really bad UX.

After working hard on trying to solve it I finally realize it's should be easy, as easy as adding two words: Mode=OneWay
The final XAML looks like this:

            <ComboBox
                x:Name="ProcessBox"
                SelectedValue="{Binding Mode=OneTime, Path=Value.Process}"
                DisplayMemberPath="Name"
                IsEditable="True" />

            <ComboBox
                SelectedValue="{Binding Value}"
                ItemsSource="{Binding Mode=OneWay, ElementName=ProcessBox, Path=SelectedValue.Activities}"
                DisplayMemberPath="DisplayName"
                IsEditable="True" />

This way when this editor is presented for an already selected activity only the first time it is display the ProcessBox is bound to the process of the selected activity, from that moment on no binding is done from the selected activity (Value) to the process combo box.

In conclusion
When you have a cascading editor you can use Binding Mode of OneTime to bind the cascade controls that do not represent the final value and have a great, easy, working cascade control without code.

Thank you OneTime Binding Mode.

No comments:

Post a Comment