2012-08-03 57 views
2

在我的窗口中,我有一個TreeView和TextBox。假設TextBox用於編寫自定義腳本,並且TreeView是一種選擇要插入的函數的方法;請考慮Crystal Report腳本編輯器。用戶選擇子項後,TreeView自動選擇父項

我的目標是讓用戶單擊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時發生。如果我只將數據更改爲一個級別,則此設置正常工作。

任何想法?

回答

5

核心問題是在事件處理程序中有一個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說:

操作被添加到在指定 的DispatcherPriority分派器的事件隊列中。

所以,無論在那裏你調用BeginInvoke,當調用可能發生在最近的一次任務的優先級是當前操作的執行結束之後:在beginInvoked操作「推」某處調度隊列,它在單個線程上工作。

+0

謝謝文森特。它完美的作品。 – Josh 2012-08-06 14:00:04

+0

今天遇到了這個討厭的問題,解決方案也適用於我......我們如何確定'BeginInvoke'將始終「延期」焦點足夠長? – Tekito 2014-05-14 23:12:22

+0

@Tekito:我編輯(希望)澄清。 – GameAlchemist 2014-05-14 23:28:56

相關問題