C# TreeView/TextBox键盘交互存在许多问题

C# TreeView/TextBox键盘交互存在许多问题,c#,wpf,textbox,treeview,focus,C#,Wpf,Textbox,Treeview,Focus,我有一个树视图,里面有文本框。我希望文本框不可写,无论是通过使其只读、禁用或使其不可聚焦或其他方式,除非它们接收到双击事件或选中包含它们的TreeView项并按下某个键,此时,他们应该获得焦点并选择所有文本,并允许正常文本编辑,直到失去焦点,此时他们应该返回到不可写状态。同时,我希望能够使用鼠标键或箭头键浏览TreeView 我当前的尝试将此作为TreeView结构: <TreeView name="EnrtyView" PreviewKeyDown="KeyNav"> &l

我有一个树视图,里面有文本框。我希望文本框不可写,无论是通过使其只读、禁用或使其不可聚焦或其他方式,除非它们接收到双击事件或选中包含它们的TreeView项并按下某个键,此时,他们应该获得焦点并选择所有文本,并允许正常文本编辑,直到失去焦点,此时他们应该返回到不可写状态。同时,我希望能够使用鼠标键或箭头键浏览TreeView

我当前的尝试将此作为TreeView结构:

<TreeView name="EnrtyView" PreviewKeyDown="KeyNav">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type self:Entry}" ItemsSource="{Binding Children}">
            <StackPanel Orientation="Horizontal">
                <TextBox Text="{Binding Name}" MouseDoubleClick="TextEdit" LostFocus="StopEdit" IsReadOnly="False" />
                <TextBlock Text=" - " Visibility="{Binding ValueVisible}" Focusable="False" />
                <TextBox Text="{Binding Value}" MouseDoubleClick="TextEdit" LostFocus="StopEdit" Visibility="{Binding ValueVisible}" IsReadOnly="False" />
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>
它有以下问题:

  • 文本框从树视图中窃取焦点,使键盘导航变得不可能。
    • 使文本框不可聚焦或禁用它们可以修复此问题,但也会使它们无法接收MouseDoubleClick事件
  • TreeView的默认KeyDown行为并不总是被覆盖,这会导致某些键产生意外的效果。
    • 覆盖其他事件似乎没有帮助。由于上述文本框盗取焦点的问题,测试很困难
  • 当按下某个键(使用类似
    ((TextBox)((StackPanel)((TreeViewItem)(EntryView.ItemContainerGenerator.ContainerFromItem(EntryView.SelectedItem))).Header)).Children[0])之类的键时,开始编辑文本框的明显方式不起作用,可能是因为虚拟化过度
这些都是可以解决的吗?我现在写自己的TreeView类更好吗

编辑:


根据R.Rusev的建议,我尝试将
e.Handled=true
添加到我的PreviewKeyDown事件处理程序中。虽然这阻止了前两个问题,但它揭示了我更改TreeView选择的策略实际上没有起作用,只是TreeView的默认行为泄露了出来,这就给我留下了最后一个问题,我怀疑过度的虚拟化会直接阻止对TreeView项的任何合理访问。

您可以尝试覆盖TreeView上的PreviewKeyDown,并像这样处理它

protected override void OnPreviewKeyDown( KeyEventArgs e )
{
    if (!Editing)
    {
        if ( e.Key == Key.Left )
        {
            ((Entry)(EntryView.SelectedItem)).GetNextLeft().IsSelected = true;
            e.Handled = true;
        }
        else if ( e.Key == Key.Right )
        {
            ((Entry)(EntryView.SelectedItem)).GetNextRight().IsSelected = true;                
            e.Handled = true;
        }
        else if ( e.Key == Key.Up )
        {
            ((Entry)(EntryView.SelectedItem)).GetNextUp().IsSelected = true;
            e.Handled = true;
        }
        else if ( e.Key == Key.Down )
        {
            ((Entry)(EntryView.SelectedItem)).GetNextDown().IsSelected = true;
            e.Handled = true;
        }
        else if ( e.Key == Key.Tab || e.Key == Key.Enter || e.Key == Key.Space )
        {
             //Nothing here seems to work.
            e.Handled = true;
        }
    }
}
编辑


抱歉,没有注意到您使用了PreviewKeyDown。也就是说,您仍然缺少将阻止默认处理事件的
e.Handled=true

部分答案,可能是可用的最佳答案:


通过将
KeyboardNavigation.DirectionalNavigation=“None”
添加到我的数据模板中的StackPanel并使用TreeView的默认行为,我的第一个问题得到了解决,第二个问题变得毫无意义。我的以编程方式选择项目的代码神秘地开始工作,尽管它有一个问题(虽然我可以以编程方式选择项目,但它们不会成为焦点),但它与我的原始问题完全分离,因此我将发布一个新问题。我的第三个问题似乎完全无法解决。目前我拥有的最佳解决方法是,由于某种原因,
Tab
Ctrl+Tab
导航的行为是不同的,即使它们被设置为相同,因此,
Tab
不会在树的项目中导航。这就留下了一个问题,即在树导航和文本编辑之间转换需要鼠标单击或单步通过
选项卡的界面返回树。

这正是我当前正在做的。您应该添加e.Handled,以便其他订阅者不会对该事件做任何事情(如文本框)对不起,我没有注意到这一变化。这似乎解决了前两个问题,但它揭示了另一个我因为第二个问题而没有注意到的问题。请参阅我的编辑。
protected override void OnPreviewKeyDown( KeyEventArgs e )
{
    if (!Editing)
    {
        if ( e.Key == Key.Left )
        {
            ((Entry)(EntryView.SelectedItem)).GetNextLeft().IsSelected = true;
            e.Handled = true;
        }
        else if ( e.Key == Key.Right )
        {
            ((Entry)(EntryView.SelectedItem)).GetNextRight().IsSelected = true;                
            e.Handled = true;
        }
        else if ( e.Key == Key.Up )
        {
            ((Entry)(EntryView.SelectedItem)).GetNextUp().IsSelected = true;
            e.Handled = true;
        }
        else if ( e.Key == Key.Down )
        {
            ((Entry)(EntryView.SelectedItem)).GetNextDown().IsSelected = true;
            e.Handled = true;
        }
        else if ( e.Key == Key.Tab || e.Key == Key.Enter || e.Key == Key.Space )
        {
             //Nothing here seems to work.
            e.Handled = true;
        }
    }
}