我有一个WPF TreeView,想要在所有没有Child的TreeViewItem上监听doubleclicks。我的TreeView看起来像这样:
TreeView的内容生成如下:
TreeViewItem tvi = new TreeViewItem();
tvi.Header = groupModel.Name;
treeView.Items.Add(tvi);
foreach(Model m in models) {
TreeViewItem t = new TreeViewItem();
t.Header = model.Name;
tvi.Items.Add(t);
}
在我的XAML文件中,我定义了一个EventSetter,它应该在单击TreeViewItem时触发:
<TreeView x:Name="treeView" BorderThickness="0">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<EventSetter Event="MouseDoubleClick" Handler="OnTreeItemDoubleClick"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
在我的代码背后,我定义了处理程序:
public void OnTreeItemDoubleClick(object sender, EventArgs args)
{
TreeViewItem tvi = (TreeViewItem)sender;
}
当我双击任何TreeViewItem时,会触发Handler,但每次发送者都是TreeViewItem“Level 1”。我想获得被点击的实际TreeViewItem。我该如何做到这一点?
编辑(暂时解决方法)
我一直在想复杂的方法。我只是在生成TreeViewItem时将Handler附加到MouseDoubleClick事件:
t.MouseDoubleClick += OnTreeItemDoubleClick;
我仍然对所描述问题的解决方案感兴趣,并且想知道为什么路由事件不是由嵌套最多的孩子触发的。
答案 0 :(得分:2)
我注意到如果你没有使用HierarchicalDataTemplate
和数据绑定,而是在代码中添加项目,那么EventSetter
仅为树的第一级设置事件。我想知道为什么会这样(我自己还没有找到他的问题的答案)。
解决方法是只在代码中订阅事件(因为您无论如何都要手动添加项目):
TreeViewItem tt = new TreeViewItem();
tt.Header = "some item";
tt.MouseDoubleClick += new MouseButtonEventHandler(OnTreeItemDoubleClick);
注意您在处理程序中使用EventArgs
,它应该是MouseButtonEventArgs
。
此外,由于每个TreeViewItem
都位于其父级的可视树中,因此该事件将向下冒泡,因此如果您单击已分配MouseDoubleClick
的树叶并且它具有2个父级,则该事件将被召唤3次。只有在您检查OriginalSource
:
public void OnTreeItemDoubleClick(object sender, MouseButtonEventArgs e)
{
TreeViewItem clickedItem = TryGetClickedItem(treeView, e);
if (clickedItem == null || clickedItem!=sender)
return;
//e.Handled = true; // if you want to to cancel expanded/collapsed toggle
Console.WriteLine(clickedItem.Header);
}
TreeViewItem TryGetClickedItem(TreeView treeView, MouseButtonEventArgs e)
{
var hit = e.OriginalSource as DependencyObject;
while (hit != null && !(hit is TreeViewItem))
hit = VisualTreeHelper.GetParent(hit);
return hit as TreeViewItem;
}