我正试着跟随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));
}
}和xaml中声明的TextBlock:
<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不工作!我怎样才能做我想做的事呢?
发布于 2010-05-04 07:03:47
问题是SetBinding调用清除了之前的任何绑定。因此,当您设置到Num2的绑定时,您正在清除到Num1的绑定。这是因为依赖属性绑定不能有多个源--它怎么知道要使用哪个源呢?(当然,这忽略了MultiBinding的用法,但在这种情况下这对您没有帮助)。
可以这样做的方法是将MyClass设置为DependencyObject、Num1和Num2依赖属性。然后,您可以将Num2绑定到TextBox的Text属性,每当文本从Num1接收到更新时,Num2就会被更新。
一张图片胜过千言万语--你正在尝试做的事情显示在左边。您需要做的如右图所示:
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。现在让我们来看看window的代码隐藏:
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属性-这将创建一个跨线程的异常。为了绕过这一点,我们只需使用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
https://stackoverflow.com/questions/2761531
复制相似问题