2010-05-03 74 views
2

的我試圖做好後續數據綁定鏈數據綁定

Property -> DependencyProperty -> Property 

但我有麻煩了。 例如, 我們已經有兩個屬性的簡單類實現INotifyPropertyChanged:

<TextBlock Name="tb" FontSize="20" Foreground="Red" Text="qwerqwerwqer" /> 

現在讓我們試圖NUM1結合tb.Text:

public class MyClass : INotifyPropertyChanged 
    { 
     private string _num1; 
     public string Num1 
     { 
      get { return _num1; } 
      set 
      { 
       _num1 = value; 
       OnPropertyChanged("Num1"); 
      } 
     } 

     private string _num2; 
     public string Num2 
     { 
      get { return _num2; } 
      set 
      { 
       _num2 = value; 
       OnPropertyChanged("Num2"); 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

     public void OnPropertyChanged(string e) 
     { 
      PropertyChangedEventHandler handler = PropertyChanged; 
      if (handler != null) handler(this, new PropertyChangedEventArgs(e)); 
     } 
    } 

而TextBlock的在XAML中宣佈

private MyClass _myClass = new MyClass(); 
     public MainWindow() 
     { 
      InitializeComponent(); 

      Binding binding1 = new Binding("Num1") 
            { 
             Source = _myClass, 
             Mode = BindingMode.OneWay 
            }; 

      Binding binding2 = new Binding("Num2") 
      { 
       Source = _myClass, 
       Mode = BindingMode.TwoWay 
      }; 

      tb.SetBinding(TextBlock.TextProperty, binding1); 

      //tb.SetBinding(TextBlock.TextProperty, binding2); 


      var timer = new Timer(500) {Enabled = true,}; 

      timer.Elapsed += (sender, args) => _myClass.Num1 += "a"; 

      timer.Start(); 


     } 

它運作良好。但是,如果我們取消註釋該字符串

tb.SetBinding(TextBlock.TextProperty, binding2); 

然後TextBlock什麼都不顯示。 DataBinding不起作用!我該如何做我想做的事?

回答

10

問題是SetBinding調用清除了以前的任何綁定。因此,當您將綁定設置爲Num2時,您將清除對Num1的綁定。發生這種情況是因爲依賴項屬性綁定不能有多個源 - 它如何知道使用哪一個? (當然,這忽略了MultiBinding的使用,但在這種情況下這不會起到幫助作用)。

可以這樣做的方法是使MyClassDependencyObjectNum1Num2依賴項屬性。然後,您可以將Num2綁定到TextBoxText屬性,並且Num2將在文本從Num1收到更新時更新。

一張圖片勝過千言萬語 - 你想要做的事情顯示在左邊。你需要做的是顯示在右側:

alt text http://img339.imageshack.us/img339/448/twosources.png

決定嘗試了這一點,以確保我的邏輯是合理的,而事實上它的工作原理,但也有一些技巧。對於初學者來說,這裏是新MyClass代碼:

public class MyClass : FrameworkElement 
{ 
    public static readonly DependencyProperty Num1Property = 
     DependencyProperty.Register("Num1", typeof(string), typeof(MyClass)); 

    public static readonly DependencyProperty Num2Property = 
     DependencyProperty.Register("Num2", typeof(string), typeof(MyClass)); 

    public string Num1 
    { 
     get { return (string)GetValue(Num1Property); } 
     set { SetValue(Num1Property, value); } 
    } 

    public string Num2 
    { 
     get { return (string)GetValue(Num2Property); } 
     set { SetValue(Num2Property, value); } 
    } 
} 

沒什麼可怕在這裏,只需用DependencyProperty更換您的INotifyPropertyChanged。現在讓我們看看窗戶代碼隱藏:

public partial class DataBindingChain : Window 
{ 
    public MyClass MyClass 
    { 
     get; 
     set; 
    } 

    public DataBindingChain() 
    { 
     MyClass = new MyClass(); 

     InitializeComponent(); 

     Binding binding1 = new Binding("Num1") 
     { 
      Source = MyClass, 
      Mode = BindingMode.OneWay 
     }; 

     Binding binding2 = new Binding("Text") 
     { 
      Source = tb, 
      Mode = BindingMode.OneWay 
     }; 

     tb.SetBinding(TextBlock.TextProperty, binding1); 
     MyClass.SetBinding(MyClass.Num2Property, binding2); 

     var timer = new Timer(500) { Enabled = true, }; 

     timer.Elapsed += (sender, args) => Dispatcher.Invoke(UpdateAction, MyClass); 

     timer.Start(); 
    } 

    Action<MyClass> UpdateAction = (myClass) => { myClass.Num1 += "a"; }; 
} 

這就是奇蹟發生:我們設置了兩個綁定。第一個綁定TextBlock.TextNum1,第二個綁定Num2TextBlock.Text。現在我們有一個場景,就像我向您展示的圖片的右側 - 一個數據綁定鏈。另一個神奇之處在於,我們無法更新與創建的線程不同的線程上的Num1屬性 - 這會創建一個跨線程異常。爲了繞過這個,我們只需使用Dispatcher就可以在UI線程上調用更新。

最後,XAML用於演示:

<Window x:Class="TestWpfApplication.DataBindingChain" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Title="DataBindingChain" Height="300" Width="300" 
DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 
    <TextBlock Name="tb" Grid.Row="0" FontSize="20" Foreground="Red"/> 
    <TextBlock Name="tb2" Grid.Row="1" FontSize="20" Foreground="Blue" Text="{Binding MyClass.Num2}"/> 
</Grid> 

瞧!成品:

alt text http://img163.imageshack.us/img163/6114/victorynf.png

+0

哇!老兄,我真的很喜歡你的答案!但我忘了提到,實際上我的屬性位於繼承自WinForms控件的類中,這就是爲什麼我不能使用依賴屬性:( )您的解決方案對於被問及的問題非常有用,遺憾的是我無法將其應用於我的真實任務 – Neir0 2010-05-04 00:47:16

+1

這是一個很糟糕的方法,它表明你可能需要重新思考你真正想要完成什麼,這個解決方案的本質是使用UI來控制兩個非UI對象之間的關係屬性,最終如何在UI中完成而不是在代碼中? – 2010-05-04 03:44:23

+0

那麼你可以在該場景中使用綁定模式「OneWayToSource」,但是你仍然需要在兩個不同的對象上設置綁定 - 你但是請記住,設置第二個綁定會清除已經設置的綁定,因此您需要重新定位您的一些屬性。 – Charlie 2010-05-04 14:40:22