Since the SelectedItemChanged
event is triggered after the SelectedItem
has already changed, you can't really cancel the event at this point.
What you can do is listen for mouse-clicks and cancel them before the SelectedItem
gets changed.
Since the SelectedItemChanged
event is triggered after the SelectedItem
has already changed, you can't really cancel the event at this point.
What you can do is listen for mouse-clicks and cancel them before the SelectedItem
gets changed.
Instead of selecting for Selected/Unselected, a better route might be to hook into PreviewMouseDown. The preblem with handling a Selected and Unselected event is that the event has already occurred when you receive the notification. There is nothing to cancel because it's already happened.
On the other hand, Preview events are cancelable. It's not the exact event you want but it does give you the oppuritunity to prevent the user from selecting a different node.
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:
private object _LastSelection = null;
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (IsUpdated)
{
MessageBoxResult result = MessageBox.Show("The current record has been modified. Are you sure you want to navigate away? Click Cancel to continue editing. If you click OK all changes will be lost.", "Warning", MessageBoxButton.OKCancel, MessageBoxImage.Hand);
switch (result)
{
case MessageBoxResult.Cancel:
e.Handled = true;
// disable event so this doesn't go into an infinite loop when the selection is changed to the cached value
PersonListView.SelectionChanged -= new SelectionChangedEventHandler(OnSelectionChanged);
PersonListView.SelectedItem = _LastSelection;
PersonListView.SelectionChanged += new SelectionChangedEventHandler(OnSelectionChanged);
return;
case MessageBoxResult.OK:
// revert the object to the original state
LocalDataContext.Persons.GetOriginalEntityState(_LastSelection).CopyTo(_LastSelection);
IsUpdated = false;
Refresh();
break;
default:
throw new ApplicationException("Invalid response.");
}
}
// cache the selected item for undo
_LastSelection = PersonListView.SelectedItem;
}
CAMS_ARIES:
XAML:
code :
private bool ManejarSeleccionNodoArbol(Object origen)
{
return true; // with true, the selected nodo don't change
return false // with false, the selected nodo change
}
private void Arbol_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.Source is TreeViewItem)
{
e.Handled = ManejarSeleccionNodoArbol(e.Source);
}
}
private void Arbol_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Source is TreeViewItem)
{
e.Handled=ManejarSeleccionNodoArbol(e.Source);
}
}
UPDATE
Realized I could put the logic in SelectedItemChanged instead. A little cleaner solution.
Xaml
<TreeView Name="c_treeView"
SelectedItemChanged="c_treeView_SelectedItemChanged">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Code behind. I have some classes that is my ItemsSource of the TreeView so I made an interface (MyInterface) that exposes the IsSelected property for all of them.
private MyInterface m_selectedTreeViewItem = null;
private void c_treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (m_selectedTreeViewItem != null)
{
if (e.NewValue == m_selectedTreeViewItem)
{
// Will only end up here when reversing item
// Without this line childs can't be selected
// twice if "No" was pressed in the question..
c_treeView.Focus();
}
else
{
if (MessageBox.Show("Change TreeViewItem?",
"Really change",
MessageBoxButton.YesNo,
MessageBoxImage.Question) != MessageBoxResult.Yes)
{
EventHandler eventHandler = null;
eventHandler = new EventHandler(delegate
{
c_treeView.LayoutUpdated -= eventHandler;
m_selectedTreeViewItem.IsSelected = true;
});
// Will be fired after SelectedItemChanged, to early to change back here
c_treeView.LayoutUpdated += eventHandler;
}
else
{
m_selectedTreeViewItem = e.NewValue as MyInterface;
}
}
}
else
{
m_selectedTreeViewItem = e.NewValue as MyInterface;
}
}
I haven't found any situation where it doesn't revert back to the previous item upon pressing "No".