I've got a WPF application with a Treeview control.
When the user clicks a node on the tree, other TextBox, ComboBox, etc. controls on the page are populated with appropriate values.
The user can then make changes to those values and save his or her changes by clicking a Save button.
However, if the user selects a different Treeview node without saving his or her changes, I want to display a warning and an opportunity to cancel that selection.
XAML...
<TreeView Name="TreeViewThings"
...
TreeViewItem.Unselected="TreeViewThings_Unselected"
TreeViewItem.Selected="TreeViewThings_Selected" >
Visual Basic...
Sub TreeViewThings_Unselected(ByVal sender As System.Object, _ ByVal e As System.Windows.RoutedEventArgs) Dim OldThing As Thing = DirectCast(e.OriginalSource.DataContext, Thing) If CancelDueToUnsavedChanges(OldThing) Then 'put canceling code here End If End Sub Sub TreeViewThings_Selected(ByVal sender As System.Object, _ ByVal e As System.Windows.RoutedEventArgs) Dim NewThing As Thing = DirectCast(e.OriginalSource.DataContext, Thing) PopulateControlsFromThing(NewThing) End Sub
How can I cancel those unselect/select events?
Update: I've asked a follow-up question...
How do I properly handle a PreviewMouseDown event with a MessageBox confirmation?
You can't cancel the event like you can, for example, a Closing event. But you can undo it if you cache the last selected value. The secret is you have to change the selection without re-firing the SelectionChanged event. Here's an example:
I solved this problem for 1 tree view and display of 1 document at a time. This solution is based on an attachable behavior that can be attached to a normal treeview:
and the code for the behavior is this:
In this example I am showing a blocking message box in order to block the PreviewMouseDown event when it occurs. The event is then handled to signal that selection is cancelled or it is not handled to let the treeview itself handle the event by selecting the item that is about to be selected.
The behavior then invokes a bound command in the viewmodel if the user decides to continue anyway (PreviewMouseDown event is not handled by attached behavior and bound command is invoked.
I guess the message box showing could be done in other ways but I think its essential here to block the event when it happens since its otherwise not possible to cancel it(?). So, the only improve I could possible think off about this code is to bind some strings to make the displayed message configurable.
I have written an article that contains a downloadable sample since this is otherwise a difficult area to explain (one has to make many assumptions about missing parts that and the may not always be shared by all readers)
Here is an article that contains my results: http://www.codeproject.com/Articles/995629/Cancelable-TreeView-Navigation-for-Documents-in-WP
Please comment on this solution and let me know if you see room for improvement.
You could create your custom control that derives from TreeView and then override the OnSelectedItemChanged method.
Before calling the base, you could first fire a custom event with a CancelEventArgs parameter. If the parameter.Cancel become true, then don't call the base, but select the old item instead (be careful that the OnSelectedItemChanged will be called again).
Not the best solution, but at least this keeps the logic inside the tree control, and there is not chance that the selection change event fires more than it's needed. Also, you don't need to care if the user clicked the tree, used the keyboard or maybe the selection changed programatically.