2010-10-10 48 views
0

我的工作,其中Repository對象通過包含modified版本TextBox的,它支持結合SelectionStartSelectionLength,和VerticalOffset一個DataTemplate顯示的應用文本框。WPF-問題的在的DataTemplate

的DataTemplate中看起來是這樣的:

<DataTemplate DataType="{x:Type m:Repository}"> 
<controls:ModdedTextBox 
x:Name="textBox" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" 
BindableSelectionStart="{Binding SelectionStart, UpdateSourceTrigger=PropertyChanged}" 
BindableSelectionLength="{Binding SelectionLength, UpdateSourceTrigger=PropertyChanged}" 
BindableVerticalOffset="{Binding VerticalOffset, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
</DataTemplate> 

的問題是,當我改變當前正在顯示的Repository;在SelectionStartSelectionLengthVerticalOffset一切似乎越來越設置爲0,即使在Repository對象的那些屬性不爲0

我認爲這是在瞬間顯示的文本之前當SelectionStart發生, SelectionLengthVerticalOffset不能大於0.這不僅會將TextBox的實際屬性設置爲零,還會更新綁定並將Repository對象的屬性設置爲零。

有什麼辦法可以防止這種情況發生?

- 編輯 -

我不知道是否張貼DL鏈接到項目是一個沒有沒有或沒有SO,但這裏是一個項目的鏈接我創建說明問題我有:http://dl.dropbox.com/u/1520079/RepositoryProblemDemo.zip

當您運行demo-app時,您可以單擊「Switch Repository」按鈕來更改文本框中顯示的存儲庫。如果您查看文本框的右側,當切換到另一個時,當前存儲庫的屬性都將設置爲零。

此演示與我的實際應用程序的區別在於,我的應用程序存儲庫將通過熱鍵切換,而不是按鈕。

+0

您可以發佈有關Bindable ***依賴項屬性如何創建/綁定到基礎選擇屬性的信息嗎? – 2010-10-25 08:57:38

+0

您的綁定是否需要雙向並在PropertyChanged上觸發,或者您是否可以使用OneWay或LostFocus? – 2010-10-25 09:40:03

+0

我鏈接到這個問題:http://stackoverflow.com/questions/1175618/how-to-bind-selectionstart-property-of-text-box/1849539#1849539 – Justin 2010-10-26 00:00:17

回答

1

的問題是由於一個事實,即綁定在串行計算,當Text屬性更改將導致所有選擇信息被刪除(您可以通過把斷點您ModdedTextBox事件處理程序見本)。由於BindableSelection ...綁定在此時仍處於活動狀態,因此會導致選擇信息被重置。

根據您想要的確切行爲有可能是一種方法來解決這個問題,但你需要了解更多詳情...

編輯迴應評論: 該解決方案ISN 't 完全是回答你原來的問題,它可能不是很好的做法,但它至少工作...

試着改變你的ModdedTextBox以便不用爲選擇信息暴露的可綁定屬性,暴露類型庫的單一DP並綁定到:

<local:ModdedTextBox 
       x:Name="textBox" 
       Repository="{Binding CurrentRepository}" 
       TextWrapping="Wrap" 
       /> 

然後把手上的DP改變的事件設置文本框屬性:

public static DependencyProperty RepositoryProperty = 
       DependencyProperty.Register("Repository", 
       typeof(Repository), typeof(ModdedTextBox), new PropertyMetadata(null, OnRepositoryChanged)); 

    public Repository Repository 
    { 
     get { return (Repository)base.GetValue(RepositoryProperty); } 
     set { base.SetValue(RepositoryProperty, value); } 
    } 

    private static void OnRepositoryChanged(DependencyObject senderObject, DependencyPropertyChangedEventArgs e) 
    { 
     var sender = (ModdedTextBox)senderObject; 
     var oldRepository = e.OldValue as Repository; 
     var newRepository = e.NewValue as Repository; 
     if (oldRepository != null) 
     { 
      oldRepository.Text = sender.Text; 
      oldRepository.SelectionStart = sender.SelectionStart; 
      //etc 
     } 

     if (newRepository != null) 
     { 
      sender.Text = newRepository.Text; 
      sender.SelectionStart = newRepository.SelectionStart; 
      //etc 
     } 
    } 

這實質上是去除了綁定評估的序列性質。

注意:您也可以使用附加屬性實現相同的功能,這比繼承TextBox更好,但這更接近您的原始嘗試,因此我更容易解釋!

+0

我不明白我該如何解決這個問題。你可以進入更多的細節?你需要更多信息嗎? – Justin 2010-10-27 04:02:33

+0

我不確定它是否能夠「固定」,因爲它的行爲與您所期望的相同。我的意思是說,可能有另一種方法來達到你想要的結果 - 你想對選擇信息做什麼? – 2010-10-27 07:48:40

+0

我希望它能夠在存儲庫之間切換時恢復選擇信息。 – Justin 2010-10-27 12:29:58

0

這裏是重寫其他解決方案。這個考慮到文本屬性沒有被綁定在其他屬性之前。


using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 

namespace WpfApplication1 
{ 
    public class SelectionBindingTextBox : TextBox 
    { 
     public static readonly DependencyProperty BindableSelectionStartProperty = 
      DependencyProperty.Register(
      "BindableSelectionStart", 
      typeof(int), 
      typeof(SelectionBindingTextBox), 
      new PropertyMetadata(OnBindableSelectionStartChanged)); 

     public static readonly DependencyProperty BindableSelectionLengthProperty = 
      DependencyProperty.Register(
      "BindableSelectionLength", 
      typeof(int), 
      typeof(SelectionBindingTextBox), 
      new PropertyMetadata(OnBindableSelectionLengthChanged)); 

     private bool isBindingComplete = false; 

     public SelectionBindingTextBox() 
      : base() 
     { 
      this.SelectionChanged += this.OnSelectionChanged; 
      this.TextChanged += this.OnTextChanged; 
     } 

     public int BindableSelectionStart 
     { 
      get 
      { 
       return (int)this.GetValue(BindableSelectionStartProperty); 
      } 

      set 
      { 
       this.SetValue(BindableSelectionStartProperty, value); 
      } 
     } 

     public int BindableSelectionLength 
     { 
      get 
      { 
       return (int)this.GetValue(BindableSelectionLengthProperty); 
      } 

      set 
      { 
       this.SetValue(BindableSelectionLengthProperty, value); 
      } 
     } 


     private static void OnBindableSelectionStartChanged(DependencyObject dependencyObject, 
      DependencyPropertyChangedEventArgs args) 
     { 
      var textBox = dependencyObject as SelectionBindingTextBox; 

      if (textBox.isBindingComplete) 
      { 
       textBox.SetupSelection(); 
      } 
     } 

     private static void OnBindableSelectionLengthChanged(DependencyObject dependencyObject, 
      DependencyPropertyChangedEventArgs args) 
     { 
      var textBox = dependencyObject as SelectionBindingTextBox; 
      if (textBox.isBindingComplete) 
      { 
       textBox.SetupSelection(); 
      } 
     } 

     private void OnSelectionChanged(object sender, RoutedEventArgs e) 
     { 
      if (isBindingComplete) 
      { 
       this.BindableSelectionStart = this.SelectionStart; 
       this.BindableSelectionLength = this.SelectionLength; 
      } 
     } 

     private void OnTextChanged(object sender, RoutedEventArgs e) 
     { 
      if (!isBindingComplete) 
      { 
       SetupSelection(); 
      } 
      isBindingComplete = true; 
     } 

     private void SetupSelection() 
     { 
      // this.Focus(); 
      this.SelectionLength = this.BindableSelectionLength; 
      this.SelectionStart = this.BindableSelectionStart; 
     } 
    } 
} 

+0

該文本框始終是重點。 – Justin 2010-10-25 04:31:59

0

綁定的更新取決於WPF或Silverlight引擎將評估的順序,看起來像您的SelectionStart和SelectionEnd綁定在Text之前更新,所以當Text被更改時,SelectionStart和SelectionEnd都會更改回零。

的唯一方法是掛鉤的TextChanged事件,並刷新SelectionStart和選定結束或WPF可以延長文本框的綁定如下

public class MyTextBox : TextBox{ 

    protected override OnTextChanged(TextChangedEventArgs e){ 
     BindingExpression be = this.GetBindingExpression(SelectionStartProperty); 
     if(be!=null){ 
      be.UpdateTarget(); 
     } 
     be = this.GetBindingExpression(SelectionEndProperty); 
     if(be!=null){ 
      be.UpdateTarget(); 
     } 
     be = this.GetBindingExpression(VerticalOffsetProperty); 
     if(be!=null){ 
      be.UpdateTarget(); 
     } 
    } 

} 

那麼這裏有一個小竅門,你還是得上述改變邏輯適合你的邏輯,因爲每次更新文本都會更新綁定,所以你必須找出什麼時候刷新這些綁定。因爲這會一直無法在運行時更改文本框的值,因爲文本將被修改並且選擇僅會轉到上一次選擇。