【问题标题】:TreeView auto-selecting parent after user selects child用户选择子项后 TreeView 自动选择父项
【发布时间】:2012-08-01 22:41:36
【问题描述】:

在我的窗口中,我有一个 TreeView 和 TextBox。假设 TextBox 用于编写自定义脚本,而 TreeView 是一种选择要插入的函数的方法;想想 Crystal Report 脚本编辑器。

我的目标是让用户单击 TreeView 的其中一个子项并将该子项插入到 TextBox 中。子节点是一个函数签名,位于父节点下。然后用户可以导航到文本框,选择一个函数参数并将其替换为另一个函数签名。为此,我处理了 TreeView 的 SelectedItemChanged 事件,设置了 TextBox 的 SelectedText,然后尝试在更改后突出显示文本。

TextBox 的 SelectedText 已正确交换。但是,文本没有被突出显示,滚动条也没有滚动到选定的文本。

这是我为重现行为而编写的测试项目中的 XAML:

  <Window x:Class="SelectedTextWeirdness.MainWindow"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib"
          xmlns:SelectedTextWeirdness="clr-namespace:SelectedTextWeirdness" Title="MainWindow" Width="600" Height="600"
          x:Name="Me">
     <Grid>
        <Grid.RowDefinitions>
           <RowDefinition Height="Auto" />
           <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TreeView Grid.Row="0" x:Name="treeView" ItemsSource="{Binding ElementName=Me, Path=TreeViewItems, Mode=TwoWay}" 
                  SelectedItemChanged="treeView_SelectedItemChanged" Margin="10">
           <TreeView.Resources>
              <HierarchicalDataTemplate DataType="{x:Type SelectedTextWeirdness:Parent}" ItemsSource="{Binding Children}">
                 <TextBlock Text="{Binding Name}" />
              </HierarchicalDataTemplate>
              <DataTemplate DataType="{x:Type SelectedTextWeirdness:Child}">
                 <TextBlock Text="{Binding Name}" />
              </DataTemplate>
           </TreeView.Resources>
        </TreeView>
        <TextBox Grid.Row="1" x:Name="scriptTextBox" Margin="10" Height="200" Width="Auto" FontFamily="Consolas, Courier New" 
                 HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Auto"
                 MaxLines="9999" AcceptsReturn="True" AcceptsTab="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                 Text="{Binding Path=Script, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                 />
     </Grid>
  </Window>

下面是代码隐藏:

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Data;
  using System.Windows.Documents;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Imaging;
  using System.Windows.Navigation;
  using System.Windows.Shapes;

  namespace SelectedTextWeirdness
  {
     public class Child
     {
        public string Name
        {
           get;
           set;
        }
     }

     public class Parent
     {
        public string Name
        {
           get;
           set;
        }

        public List<Child> Children
        {
           get;
           set;
        }   
     }

     /// <summary>
     /// Interaction logic for MainWindow.xaml
     /// </summary>
     public partial class MainWindow : Window
     {
        public List<Parent> TreeViewItems
        {
           get;
           set;
        }

        public MainWindow()
        {
           BuildTreeViewItems();

           InitializeComponent();
        }

        private void BuildTreeViewItems()
        {
           TreeViewItems = new List<Parent>()
                              {
                                 new Parent()
                                    {
                                       Name = "Parent1",
                                       Children =
                                          new List<Child>()
                                             {
                                                new Child() {Name = "ReallyLongFunctionNameNumber1(ReallyLongLeft1, ReallyLongRight1)"},
                                                new Child() {Name = "ReallyLongFunctionNameNumber2(ReallyLongLeft2, ReallyLongRight2)"},
                                                new Child() {Name = "ReallyLongFunctionNameNumber3(ReallyLongLeft3, ReallyLongRight3)"},
                                                new Child() {Name = "ReallyLongFunctionNameNumber4(ReallyLongLeft4, ReallyLongRight4)"},
                                                new Child() {Name = "ReallyLongFunctionNameNumber5(ReallyLongLeft5, ReallyLongRight5)"}
                                             }
                                    },
                                 new Parent()
                                    {
                                       Name = "Parent2",
                                       Children =
                                          new List<Child>()
                                             {
                                                new Child() {Name = "ReallyLongFunctionNameNumber1(ReallyLongLeft1, ReallyLongRight1)"},
                                                new Child() {Name = "ReallyLongFunctionNameNumber2(ReallyLongLeft2, ReallyLongRight2)"},
                                                new Child() {Name = "ReallyLongFunctionNameNumber3(ReallyLongLeft3, ReallyLongRight3)"},
                                                new Child() {Name = "ReallyLongFunctionNameNumber4(ReallyLongLeft4, ReallyLongRight4)"},
                                                new Child() {Name = "ReallyLongFunctionNameNumber5(ReallyLongLeft5, ReallyLongRight5)"}
                                             }
                                    }
                              };
        }

        private void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
           var tree = (TreeView)sender;
           var selectedItem = tree.SelectedItem as Child;
           if (selectedItem != null)
           {
              int selectionStart = scriptTextBox.SelectionStart;
              string selectedText = selectedItem.Name;
              scriptTextBox.SelectedText = selectedText;
              scriptTextBox.Focus();            
              scriptTextBox.Select(selectionStart, selectedText.Length);
           }
        }
     }
  }

我已尝试设置 SelectedItemChanged e.Handled = true。那没有用。我已经尝试处理 TextBox 的 LostFocus 并设置 e.Handled = true 并且没有奏效。这似乎只在我使用 HierarchicalDateTemplate 时发生。如果我将数据更改为仅一级,则此设置可以正常工作。

有什么想法吗?

【问题讨论】:

    标签: c# wpf textbox treeview selecteditemchanged


    【解决方案1】:

    核心问题是在事件处理程序中更改Focus()。通过在 BeginInvoke 中调用焦点来推迟焦点。

    类似:

    delegate void voidDelegate();
    
    private void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        var tree = (TreeView)sender;
        var selectedItem = tree.SelectedItem as Child;
        if (selectedItem != null)
        {
            int selectionStart = scriptTextBox.SelectionStart;
            string selectedText = selectedItem.Name;
            voidDelegate giveFocusDelegate = new  voidDelegate(giveFocus);  
            Dispatcher.BeginInvoke(giveFocusDelegate, new object[] { });
            scriptTextBox.SelectedText = selectedText;         
        }
    }
    
    private void giveFocus()
    {
        scriptTextBox.Focus();
    }    
    

    应该让你离目标更近。

    编辑:我们怎么知道这会起作用?

    正如the documentation for Dispatcher.BeginInvoke 所说:

    操作被添加到 Dispatcher 的事件队列中 指定 DispatcherPriority。

    因此,无论您调用 beginInvoke 的任务的优先级如何,调用可能发生的最近时间是在当前操作的执行结束之后:beginInvoked 操作被“推送”到调度程序队列的某个位置,这是有效的在一个线程上。

    【讨论】:

    • 今天遇到了这个讨厌的问题,解决方案也适用于我......我们如何确定BeginInvoke 将始终“推迟”焦点足够长的时间?
    猜你喜欢
    • 1970-01-01
    • 2018-04-28
    • 1970-01-01
    • 2016-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-17
    相关资源
    最近更新 更多