如何实现对属性的双向绑定? [英] How to implement two-way binding on a property?

查看:96
本文介绍了如何实现对属性的双向绑定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道有很多有关依赖属性的问题,我看了很多,但是他们似乎都没有解决我的问题。



我有这样的窗口:

 < Window x:Class =WpfBindingTest.MainWindow
xmlns =http: //schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml
xmlns:d = http://schemas.microsoft.com/expression/blend/2008
xmlns:mc =http://schemas.openxmlformats.org/markup-compatibility/2006
xmlns:local = clr-namespace:WpfBindingTest
mc:Ignorable =d
Title =MainWindowHeight =350Width =525
DataContext ={Binding RelativeSource = {RelativeSource Self }}>
< StackPanel>
< local:TextInputWrapper MyText ={Binding MyTextValue,Mode = TwoWay}/>
< TextBox Text ={Binding MyTextValue,Mode = TwoWay}/>
< / StackPanel>
< / Window>

其中MyTextValue只是一个字符串属性,通知更改时:

 私人字符串_myTextValue =完全不同的值; 
public string MyTextValue {get {return _myTextValue; } set {_myTextValue = value; OnPropertyChanged(); }}
public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
}

TextInputWrapper也很简单:

 < UserControl x:Class =WpfBindingTest.TextInputWrapper
xmlns =http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml
xmlns:mc =http://schemas.openxmlformats.org/markup-compatibility/2006
xmlns:d =http://schemas.microsoft.com/expression/blend/2008
xmlns:local =clr-namespace:WpfBindingTest
mc:Ignorable = d
d:DesignHeight =300d:DesignWidth =300
DataContext ={Binding RelativeSource = {RelativeSource Self}}>
< TextBox Text ={Binding MyText}>< / TextBox>
< / UserControl>

代码隐藏:

  public partial class TextInputWrapper:UserControl 
{
public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register(MyText,
typeof(string),typeof(TextInputWrapper)新的PropertyMetadata(Empty));
public TextInputWrapper()
{
InitializeComponent();
}
public string MyText
{
get {return(string)GetValue(MyTextProperty); }
set {SetValue(MyTextProperty,value); }
}

}

了解,我的窗口现在应该有两个绑定到彼此的TextBox控件。如果我将值更改为一个,另一个应该更新。



但是,我最终得到了两个单独的文本框,其中第一个文本框以文本空开头,下一个具有完全不同的值。像这样:



更改其中的任何一个文本不会在另一个中复制。



我希望他们都可以从文本完全不同的值开始,并与其值相同步(通过在MainWindow上传播更改为MyTextValue属性,并通过在此处通知更改) ,则更改将传播到另一个文本框)。在我的控制中我没有正确地实现数据绑定?

解决方案

删除作业

  DataContext ={Binding RelativeSource = {RelativeSource Self}}

从UserControl的XAML。相反,将内部绑定的 RelativeSource 设置为控件实例:

 < UserControl x:Class =WpfBindingTest.TextInputWrapper...> 
< TextBox Text ={Binding MyText,
RelativeSource = {RelativeSource AncestorType = UserControl}}/>
< / UserControl>






显式设置UserControl的DataContext可以防止继承DataContext从其父控件,即一个绑定,如

 < local:TextInputWrapper MyText ={Binding MyTextValue,Mode = TwoWay} /> 

将使用UserControl作为源对象,而不是当前的DataContext。






作为一般规则,永远不会显式设置UserControl的DataContext。


I know there are lots of questions about dependency properties, and I have looked at many of them, but none of them seems to solve my problem.

I have a Window like this:

<Window x:Class="WpfBindingTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfBindingTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <StackPanel>
        <local:TextInputWrapper MyText="{Binding MyTextValue, Mode=TwoWay}" />
        <TextBox Text="{Binding MyTextValue, Mode=TwoWay}"/>
    </StackPanel>
</Window>

Where MyTextValue is just a string property that notifies when changed:

    private string _myTextValue = "Totally different value";
    public string MyTextValue { get { return _myTextValue; } set { _myTextValue = value; OnPropertyChanged(); } }
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

TextInputWrapper is also rather simple:

<UserControl x:Class="WpfBindingTest.TextInputWrapper"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfBindingTest"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <TextBox Text="{Binding MyText}"></TextBox>
</UserControl>

Code-behind:

public partial class TextInputWrapper : UserControl
{
    public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText",
        typeof(string), typeof(TextInputWrapper), new PropertyMetadata("Empty"));
    public TextInputWrapper()
    {
        InitializeComponent();
    }
    public string MyText
    {
        get { return (string)GetValue(MyTextProperty); }
        set { SetValue(MyTextProperty, value); }
    }

}

Now as far as I have understood, my Window should now have 2 TextBox controls that are bound to eachother. As in if I change value in one, the other one should update.

However, I end up with 2 seperate TextBoxes where the first one starts with the text "Empty", and the next one has the text "Totally different value". Like this:

And changing the text en either of them does not reproduce in the other.

I would expect both of them to start out with the text "Totally different value" and be in sync with their values (by propagating changes to the MyTextValue property on MainWindow, and by notifying change there, the change would then propagate up to the other textbox). What am I missing to properly implement data-binding in my control?

解决方案

Remove the assignment

DataContext="{Binding RelativeSource={RelativeSource Self}}"

from the UserControl's XAML. Instead, set the RelativeSource of the "internal" binding to the control instance:

<UserControl x:Class="WpfBindingTest.TextInputWrapper" ...>
    <TextBox Text="{Binding MyText,
                    RelativeSource={RelativeSource AncestorType=UserControl}}"/>
</UserControl>


Explicitly setting the DataContext of a UserControl prevents inheriting the DataContext from its parent control, i.e. a Binding like

<local:TextInputWrapper MyText="{Binding MyTextValue, Mode=TwoWay}" />

would use the UserControl as source object, instead of the current DataContext.


As a general rule, never explicitly set the DataContext of a UserControl.

这篇关于如何实现对属性的双向绑定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆