Chain of DataBinding

后端 未结 1 969
情深已故
情深已故 2021-01-15 14:41

I am trying to do follow DataBinding

Property -> DependencyProperty -> Property

But i have trouble. For example, We have simple clas

相关标签:
1条回答
  • 2021-01-15 15:33

    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).

    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:

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

    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); }
        }
    }
    

    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"; };
    }
    

    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.

    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>
    

    And voila! The finished product:

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

    0 讨论(0)
提交回复
热议问题