如何在属性上实现双向绑定?

时间:2016-10-24 14:45:32

标签: c# .net wpf data-binding wpf-controls

我知道有很多关于依赖属性的问题,我已经查看了很多这些问题,但是它们似乎都没有解决我的问题。

我有一个这样的窗口:

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

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

    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也很简单:

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

代码隐藏:

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

}

现在据我所知,我的Window现在应该有两个相互绑定的TextBox控件。如果我在一个中更改值,则另一个应该更新。

然而,我最终得到了两个单独的TextBoxes,其中第一个以文本“Empty”开头,而下一个文本“文本为”Totally different value“。像这样: Screenshot

并且更改其中任何一个的文本都不会在另一个中重现。

我希望他们两个都从文本“Totally different value”开始,并与他们的值同步(通过将更改传播到MainWindow上的MyTextValue属性,并通过在那里通知更改,然后更改将传播到另一个文本框)。在我的控件中正确实现数据绑定我错过了什么?

2 个答案:

答案 0 :(得分:2)

删除作业

DataContext="{Binding RelativeSource={RelativeSource Self}}"
来自UserControl的XAML的

。而是设置&#34;内部&#34;的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。

答案 1 :(得分:0)

尝试更改此行:

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

对此:

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