数据绑定链

时间:2010-05-03 22:05:57

标签: c# wpf data-binding

我正在尝试关注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不起作用!我怎样才能做我想做的事?

1 个答案:

答案 0 :(得分:10)

问题是SetBinding调用清除了以前的任何绑定。因此,当您将绑定设置为Num2时,您将清除绑定到Num1。发生这种情况是因为依赖项属性绑定不能有多个源 - 它如何知道要使用哪一个? (当然,这忽略了MultiBinding的使用,但在这种情况下这不会帮助你)。

这样做的方法是使MyClass成为DependencyObjectNum1以及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,第二个绑定Num1Num2。现在我们有一个场景,就像我向你展示的图片的右侧 - 数据绑定链。另一个神奇之处在于我们无法更新与创建它的线程不同的线程上的TextBlock.Text属性,这会产生跨线程异常。为了绕过这个,我们只需使用Num1调用UI线程的更新。

最后,用于演示的XAML:

Dispatcher

瞧!成品:

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