带有 TextBox 子项的 TreeView SelectedItem 行为

Posted

技术标签:

【中文标题】带有 TextBox 子项的 TreeView SelectedItem 行为【英文标题】:TreeView SelectedItem behavior with TextBox children 【发布时间】:2012-04-09 02:20:51 【问题描述】:

当 TreeViewItem 是像 Textbox 这样的输入控件时,不会发生 TreeView 的 SelectedItemChanged 事件和 SelectedItem 属性。下面的示例代码通过在 TreeView SelectedItemChanged 事件中放置断点来说明问题。 This breakpoint will fire when "String Header" is selected, but not "Textbox Header".

我假设 Textbox 或 RichTextbox(我的真实应用程序)正在吃一些重要的冒泡事件。如何让 TreeView SelectedItem 对 TextBox 的行为与对 Label 等控件的行为一样?

注意:如果我能解决这个问题,我将需要双向绑定到 SelectedItem,因为我正在使用 MVVM 和 MEF。 SelectedItem 是只读的,这是我打算用 (http://silverscratch.blogspot.com/2010/11/two-way-binding-on-treeviewselecteditem.html) 解决的问题。我认为这个相关链接可能会对某人有所帮助。

XAML:

<TreeView SelectedItemChanged="TreeView_SelectedItemChanged">
    <TreeViewItem>
        <TreeViewItem.Header>
            <TextBox>
                Textbox Header
            </TextBox>
        </TreeViewItem.Header>
    </TreeViewItem>
    <TreeViewItem>
        <TreeViewItem.Header>
            String Header
        </TreeViewItem.Header>
    </TreeViewItem>
</TreeView>

代码背后:

    private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    
        // Breakpoint will fire when "String Header" Selected
        // !!! Breakpoint does not fire when Textbox Selected
        var newValue = e.NewValue;
        var oldValue = e.OldValue;
    

谢谢,

【问题讨论】:

【参考方案1】:

您应该在您的TreeView 上捕获GotFocus 事件:

<TreeView SelectedItemChanged="TreeView_SelectedItemChanged"
          GotFocus="UIElement_OnGotFocus">
   <TreeViewItem>
      <TreeViewItem.Header>
          <TextBox>Textbox Header</TextBox>
       </TreeViewItem.Header>
   </TreeViewItem>
   <TreeViewItem>
        <TreeViewItem.Header>String Header</TreeViewItem.Header>
   </TreeViewItem>
 </TreeView>

private void UIElement_OnGotFocus(object sender, RoutedEventArgs e)

    TreeViewItem item = UIHelpers.TryFindParent<TreeViewItem>   
                           ((DependencyObject) e.OriginalSource);
    if (item != null)
          item.IsSelected = true;

TryFindParent 的实现你可以在这里找到:https://***.com/a/4838168/1088908

【讨论】:

恐怕我过度简化了我的问题。我的 TreeView 的文本框 TreeViewItems 实际来自 MEF 的第 3 方程序集。长话短说,我必须处理 TreeView 上的事件。但是,您认为我可以/应该在 TreeView 级别处理这个冒泡的 GotFocus 事件吗? 当然,即使您将 GotFocus="UIElement_OnGotFocus" 移动到 TreeView,它也能正常工作。但不要忘记在处理程序中添加此检查: item != null (我已经更新了答案) 太棒了!如果可以的话,我必须结束问题。 1)出于理解目的,您知道为什么 SelectedItemChanged 会自动为 TreeViewItems 内容(如 Label 而不是 Textbox)工作 - 什么是缺席冒泡事件? 2) 在您链接的 GetParentObject 方法中,最后的手段是使用 VisualTreeHelper。为什么仅使用 VisualTreeHelper 查找父级是不够的? 1.我不确切知道,但在键盘焦点上感觉到这个问题。您知道 WPF 有两个焦点:“键盘”和“逻辑”,它们之间没有直接的依赖关系。如果使用 TextBox,它会捕获“键盘”焦点而不是“逻辑”... 2. 我很久以前就发现了这种方法,许多 WPF 驱动的人经常在示例中使用它。我在我的项目中的很多地方都使用了它,并且效果很好:) 这是具有良好 cmets 的版本sites.google.com/site/bobstechwiki/home/wpf-ji-shu-1/… 我尝试了这种方法,当我单击 TextBox 时它会选择 TreeViewItem,但它不会将光标放在 TextBox 中,直到我再次单击 TextBox(同时选择 TreeViewItem)。有没有办法选择 TreeViewItem 并在第一次单击时仍保持编辑模式处于活动状态?

以上是关于带有 TextBox 子项的 TreeView SelectedItem 行为的主要内容,如果未能解决你的问题,请参考以下文章

拖放后在Treeview中获取子项的名称

WPF 之 TreeView节点重命名

Shift+Tab 在 TreeView 控件中不起作用

在特定鼠标位置拖放到 TextBox - 显示插入符号或位置指示符

KendoUI 过滤器 TreeView

C#中按钮点击后,treeview控件怎么选中指定节点?