我正在尝试关注DataBinding
Property -> DependencyProperty -> Property
但我遇到了麻烦。 例如, 我们有一个简单的类,有两个属性实现INotifyPropertyChanged:
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中声明:
<TextBlock Name="tb" FontSize="20" Foreground="Red" Text="qwerqwerwqer" />
现在让我们尝试将Num1绑定到tb.Text:
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不起作用!我怎样才能做我想做的事?
答案 0 :(得分:10)
问题是SetBinding
调用清除了以前的任何绑定。因此,当您将绑定设置为Num2
时,您将清除绑定到Num1
。发生这种情况是因为依赖项属性绑定不能有多个源 - 它如何知道要使用哪一个? (当然,这忽略了MultiBinding
的使用,但在这种情况下这不会帮助你)。
这样做的方法是使MyClass
成为DependencyObject
和Num1
以及Num2
依赖项属性。然后,您可以将Num2
绑定到Text
的{{1}}属性,只要文本从TextBox
收到更新,Num2
就会更新。
一张图片胜过千言万语 - 你想要做的事情显示在左边。您需要做的事情显示在右侧:
alt text http://img339.imageshack.us/img339/448/twosources.png
决定尝试这一点以确保我的逻辑是合理的,确实有效,但有一些技巧。对于初学者,这是新的Num1
代码:
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); }
}
}
替换了你的INotifyPropertyChanged
。现在让我们看一下代码隐藏窗口:
DependencyProperty
这就是魔术发生的地方:我们设置了两个绑定。第一个将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.Text
,第二个绑定Num1
到Num2
。现在我们有一个场景,就像我向你展示的图片的右侧 - 数据绑定链。另一个神奇之处在于我们无法更新与创建它的线程不同的线程上的TextBlock.Text
属性,这会产生跨线程异常。为了绕过这个,我们只需使用Num1
调用UI线程的更新。
最后,用于演示的XAML:
Dispatcher
瞧!成品:
alt text http://img163.imageshack.us/img163/6114/victorynf.png