【问题标题】:Numerous problems with TreeView/TextBox keyboard interactionsTreeView/TextBox 键盘交互的许多问题
【发布时间】:2016-08-15 21:38:41
【问题描述】:

我有一个带有文本框的 TreeView。我希望 TextBoxes 不可写,无论是通过使它们成为只读还是禁用它们或使它们无法聚焦或其他方式,除非它们接收到双击事件或它们包含的 TreeViewItem 被选中并按下了某个键,此时他们应该获得焦点并选择所有文本并允许正常的文本编辑,直到失去焦点,此时他们应该返回到不可写状态。同时,我希望能够使用鼠标或箭头键导航 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>

Entry 类将 NameValue 作为字符串属性,IsSelectedIsExpanded 作为 bool 属性包括在内,以允许以编程方式选择列表中的项目,尽管 Microsoft 已尽最大努力与之相反,并且ValueVisible 作为可见性属性。相关事件处理程序转载如下:

public void TextEdit(object sender, RoutedEventArgs e)
{
    (sender as TextBox).IsReadOnly = false;
    (sender as TextBox).Focus();
    (sender as TextBox).SelectAll();
}
public void StopEdit(object sender, RoutedEventArgs e)
{
    string txt = (sender as TextBox).Text;
    if (!ValidateName(txt))
    {
        MessageBox.Show("Problem parsing name- please try again.");
        (sender as TextBox).Focus();
        (sender as TextBox).SelectAll();
        return;
    }
    (sender as TextBox).IsReadOnly = true;
    (sender as TextBox).Select(0, 0);
}

public void KeyNav(object sender, KeyEventArgs e)
{
    if (!Editing)
    {
        if (e.Key == Key.Left)
        {
            ((Entry)(EntryView.SelectedItem)).GetNextLeft().IsSelected = true;
        }
        else if (e.Key == Key.Right)
        {
            ((Entry)(EntryView.SelectedItem)).GetNextRight().IsSelected = true;
        }
        else if (e.Key == Key.Up)
        {
            ((Entry)(EntryView.SelectedItem)).GetNextUp().IsSelected = true;
        }
        else if (e.Key == Key.Down)
        {
            ((Entry)(EntryView.SelectedItem)).GetNextDown().IsSelected = true;
        }
        else if (e.Key == Key.Tab || e.Key == Key.Enter || e.Key == Key.Space)
        {
            //Nothing here seems to work.
        }
    }
}

存在以下问题:

  • TextBox 会从 TreeView 中窃取焦点,从而无法进行键盘导航。
    • 使 TextBox 无法聚焦或禁用它们可以解决此问题,但会使它们也无法接收 MouseDoubleClick 事件。
  • TreeView 的默认 KeyDown 行为并不总是被覆盖,这会导致某些键产生意想不到的效果。
    • 覆盖其他事件似乎没有帮助。由于上述文本框窃取焦点的问题,测试很困难。
  • 在敲击某个键(如((TextBox)(((StackPanel)(((TreeViewItem)(EntryView.ItemContainerGenerator.ContainerFromItem(EntryView.SelectedItem))).Header)).Children[0])))时开始编辑文本框的明显方法不起作用,可能是因为过度虚拟化。

这些都可以解决吗?此时我是否最好编写自己的 TreeView 类?

编辑:

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

【问题讨论】:

    标签: c# wpf textbox treeview focus


    【解决方案1】:

    您可以尝试在 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,这将阻止事件的默认处理。

    【讨论】:

    • 这正是我目前正在做的事情。
    • 您应该添加 e.Handled 以便其他订阅者不会对该事件执行任何操作(例如 TextBoxes)。
    • 抱歉,我没有注意到这种变化。这似乎解决了前两个问题,但事实证明它揭示了另一个我没有注意到的问题,因为第二个问题。查看我的编辑。
    【解决方案2】:

    部分答案,可能是最好的答案:

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

    【讨论】:

      猜你喜欢
      • 2011-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-19
      • 2020-11-06
      • 1970-01-01
      • 2010-11-23
      • 1970-01-01
      相关资源
      最近更新 更多