【发布时间】: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 类将 Name 和 Value 作为字符串属性,IsSelected 和 IsExpanded 作为 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