数据绑定链

Nei*_*ir0 2 c# data-binding wpf

我正在尝试按照DataBinding

Property -> DependencyProperty -> Property
Run Code Online (Sandbox Code Playgroud)

但我有麻烦.例如,我们有两个属性实现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));
        }
    }
Run Code Online (Sandbox Code Playgroud)

并且在xaml中声明了TextBlock:

<TextBlock Name="tb" FontSize="20" Foreground="Red" Text="qwerqwerwqer" />
Run Code Online (Sandbox Code Playgroud)

现在让我们尝试将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();


        }
Run Code Online (Sandbox Code Playgroud)

它运作良好.但是如果我们取消注释这个字符串

tb.SetBinding(TextBlock.TextProperty, binding2);
Run Code Online (Sandbox Code Playgroud)

然后TextBlock什么都不显示.DataBinding不起作用!我怎么能做我想要的?

Cha*_*lie 10

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

你可以做到这一点的方法是使MyClassDependencyObjectNum1Num2依赖属性.然后,您可以绑定Num2到该Text属性TextBox,并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); }
    }
}
Run Code Online (Sandbox Code Playgroud)

没有什么可怕的,只是替换你INotifyPropertyChangedDependencyProperty.现在让我们看一下窗口代码隐藏:

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"; };
}
Run Code Online (Sandbox Code Playgroud)

这就是魔术发生的地方:我们设置了两个绑定.第一个绑定TextBlock.TextNum1,第二个绑定Num2TextBlock.Text.现在我们有一个场景,就像我向你展示的图片的右侧 - 数据绑定链.另一个魔力是我们不能Num1在与创建它的线程不同的线程上更新属性 - 这将创建跨线程异常.为了绕过这个,我们只需使用.net调用UI线程的更新Dispatcher.

最后,用于演示的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>
Run Code Online (Sandbox Code Playgroud)

瞧!成品:

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