数据绑定链 [英] Chain of DataBinding
问题描述
我正在追踪DataBinding
I am trying to do follow DataBinding
Property -> DependencyProperty -> Property
但我有麻烦。
例如
我们有简单的类与两个属性实现INotifyPropertyChanged:
But i have trouble. For example, We have simple class with two properties implements 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));
}
}
在xaml中声明的TextBlock:
And TextBlock declared in xaml:
<TextBlock Name="tb" FontSize="20" Foreground="Red" Text="qwerqwerwqer" />
现在可以尝试将Num1绑定到tb.Text:
Now lets trying to bind Num1 to 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();
}
效果很好。但是如果我们取消注释这个字符串
It works well. But if we uncomment this string
tb.SetBinding(TextBlock.TextProperty, binding2);
然后TextBlock什么都不显示。 DataBinding不起作用
then TextBlock display nothing. DataBinding doesn't work! How can i to do what i want?
推荐答案
问题是, SetBinding
调用清除任何先前的绑定。所以当你设置绑定到 Num2
时,你将清除绑定到 Num1
。这是因为依赖属性绑定不能有多个来源 - 它会如何知道要使用哪个来源? (当然,这忽略了 MultiBinding
的使用,但这不会在这种情况下帮助您)。
The problem is that the SetBinding
call clears out any previous bindings. So when you set a binding to Num2
, you are clearing out the binding to Num1
. This happens because a dependency property binding cannot have multiple sources- how would it know which one to use? (Of course, this ignores the usage of a MultiBinding
, but that's not going to help you in this scenario).
您可以这样做的方法是使 MyClass
a DependencyObject
和 Num1
和 Num2
依赖关系属性。然后,您可以将 Num2
绑定到 TextBox
文本属性>,而 Num2
将在文本从 Num1
收到更新时更新。
The way you can do this is to make MyClass
a DependencyObject
and Num1
and Num2
dependency properties. Then you can bind Num2
to the Text
property of the TextBox
, and Num2
will be updated whenever the text receives an update from Num1
.
一张照片值得一千字,你想做的是左边显示的。您需要做的是显示在右侧:
A picture is worth a thousand words- what you're trying to do is shown on the left. What you need to do is shown on the right:
替代文本http://img339.imageshack.us/img339/448/twosources.png
决定尝试这样做,以确保我的逻辑是健全的,实际上它有效,但有一些技巧。对于初学者,这里是新的 MyClass
代码:
Decided to try this out to ensure my logic was sound, and indeed it works, but there are some tricks. For starters, here is the new MyClass
code:
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
。现在我们来看看窗口代码:
Nothing scary here, just replaced your INotifyPropertyChanged
with DependencyProperty
. Now let's check out the window code-behind:
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
。现在我们有一个场景,就像我向你展示的图像的右侧 - 一个数据绑定链。另一个魔力是,我们不能在不同的线程上更新$ code> Num1 属性,而不是创建跨线程异常的线程。为了绕过这个,我们只需使用 Dispatcher
在UI线程上调用更新。
This is where the magic happens: we set up two bindings. The first binds the TextBlock.Text
to Num1
, the second binds Num2
to the TextBlock.Text
. Now we have a scenario like the right side of the picture I showed you- a data-binding chain. The other magic is that we cannot update the Num1
property on a different thread from the one it was created on- that would create a cross-thread exception. To bypass this, we simply invoke an update onto the UI thread using the Dispatcher
.
最后,XAML用于演示:
Finally, the XAML used for demonstration:
<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
这篇关于数据绑定链的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!