How to implement two-way binding on a property?

假如想象 提交于 2019-12-18 09:43:08

问题


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?


回答1:


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.




回答2:


Try changing this line:

public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText",
typeof(string), typeof(TextInputWrapper), new PropertyMetadata("Empty"));

To this:

public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText",
    typeof(string), typeof(TextInputWrapper), new FrameworkPropertyMetadata("Empty", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));


来源:https://stackoverflow.com/questions/40221314/how-to-implement-two-way-binding-on-a-property

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!