首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DataBinding链

DataBinding链
EN

Stack Overflow用户
提问于 2010-05-04 06:05:57
回答 1查看 1.8K关注 0票数 2

我正试着跟随DataBinding

代码语言:javascript
复制
Property -> DependencyProperty -> Property

但我有麻烦。例如,我们有一个简单的类,有两个属性实现INotifyPropertyChanged:

代码语言:javascript
复制
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:

代码语言:javascript
复制
<TextBlock Name="tb" FontSize="20" Foreground="Red" Text="qwerqwerwqer" />

现在让我们尝试将Num1绑定到tb.Text:

代码语言:javascript
复制
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();


        }

它工作得很好。但是如果我们取消对此字符串的注释

代码语言:javascript
复制
tb.SetBinding(TextBlock.TextProperty, binding2);

然后TextBlock不显示任何内容。DataBinding不工作!我怎样才能做我想做的事呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-05-04 07:03:47

问题是SetBinding调用清除了之前的任何绑定。因此,当您设置到Num2的绑定时,您正在清除到Num1的绑定。这是因为依赖属性绑定不能有多个源--它怎么知道要使用哪个源呢?(当然,这忽略了MultiBinding的用法,但在这种情况下这对您没有帮助)。

可以这样做的方法是将MyClass设置为DependencyObjectNum1Num2依赖属性。然后,您可以将Num2绑定到TextBoxText属性,每当文本从Num1接收到更新时,Num2就会被更新。

一张图片胜过千言万语--你正在尝试做的事情显示在左边。您需要做的如右图所示:

alt text http://img339.imageshack.us/img339/448/twosources.png

我决定试一试,以确保我的逻辑是合理的,而且确实是有效的,但也有一些技巧。对于初学者,下面是新的MyClass代码:

代码语言:javascript
复制
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的代码隐藏:

代码语言:javascript
复制
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:

代码语言:javascript
复制
<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

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2761531

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档