Reputation: 865
I have a TreeView control with 2-level hierarchy. If an item of the second level is selected and a user clicks on another item, I need to ask him whether he is sure to move to another item. If his answer is 'no', I need to prevent another TreeViewItem from selection.
I try this way:
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<EventSetter Event="PreviewKeyDown" Handler="TreeViewItem_OnKeyDown" />
</Style>
</TreeView.Resources>
private void TreeViewItem_OnMouseDown(object sender, MouseButtonEventArgs e)
{
var selectedTreeViewItem = sender as TreeViewItem;
if (selectedTreeViewItem != null)
{
var myData = selectedTreeViewItem.Header as MyData;
if (myData != null && selectedNode != null)
{
if (!selectedNode.DoYouAgreeToMoveToAnotherItem())
{
e.Handled = true;
}
else
{
myTreeView.Focus();
myData.IsNodeSelected = true;
}
}
}
}
In a way that works. However, the problem is that I get OnMouseDown event twice: for the first-level item and for the second level item. For example, for this tree: Russia - Moscow - Piter USA - New-York - Boston If I click Boston, I get first event for the USA and then for Boston. So, I can't distinguish the cases:
In TreeViewItem_OnMouseDown I need to know the TreeViewItem which user clicked on.
Could you advice me, how I can determine the TreeViewItem which user clicked on in TreeViewItem_OnMouseDown? Again, if I just check a sender. It maybe USA, but actually user clicked on Boston. So I need to realize that it was Boston.
Upvotes: 2
Views: 1081
Reputation: 2535
Well this is just a rough example but you could potentially handle it something like this from code behind.
XAML
<TreeView ...>
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="treeViewItem_PreviewMouseLeftButtonDown" />
</Style>
</TreeView.Resources>
...
</TreeView>
Some Helper Methods
public static T GetFirstAncestorOfType<T>(DependencyObject source) where T : class
{
while (source != null && !(source is T))
source = VisualTreeHelper.GetParent(source);
return source as T;
}
public static MessageBoxResult DoYouAgreeToMoveToAnotherItem()
{
return MessageBox.Show("Select a different item?", "Select?", MessageBoxButton.YesNo);
}
Code Behind
private TreeViewItem _selectedItem = null;
void treeViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem tvi = GetFirstAncestorOfType<TreeViewItem>(e.OriginalSource as DependencyObject);
if (_selectedItem != null &&
tvi != null &&
tvi != _selectedItem &&
MessageBoxResult.Yes != DoYouAgreeToMoveToAnotherItem())
{
e.Handled = true;
}
else
{
// Update _selectedItem for comparison the next time this method fires.
_selectedItem = tvi;
if(_selectedItem != null)
_selectedItem.IsSelected = true;
}
}
You could also likely accomplish this with pure MVVM. I don't have time to post an example using TreeView
but the solution might involve using Dispatcher
something like the solutions offered here...
WPF: Cancel a user selection in a databound ListBox?
Upvotes: 1