如何在 属性 上实现 two-way 绑定?
How to implement two-way binding on a property?
我知道有很多关于依赖属性的问题,我也看过很多,但是 none 似乎解决了我的问题。
我有一个 Window 这样的:
<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>
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); }
}
}
据我所知,我的 Window 现在应该有 2 个彼此绑定的 TextBox 控件。就像我改变其中一个的值一样,另一个应该更新。
但是,我最终得到了 2 个单独的文本框,其中第一个以文本 "Empty" 开头,下一个以文本 "Totally different value" 开头。像这样:
并且更改其中任何一个的文本不会在另一个中重现。
我希望它们都以文本 "Totally different value" 开始并与它们的值同步(通过传播对 MainWindow 上的 MyTextValue 属性 的更改,以及通过通知那里的更改,更改将传播到另一个文本框)。在我的控制中正确实施 data-binding 我缺少什么?
尝试更改此行:
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));
删除分配
DataContext="{Binding RelativeSource={RelativeSource Self}}"
来自 UserControl 的 XAML。相反,将 "internal" 绑定的 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。
我知道有很多关于依赖属性的问题,我也看过很多,但是 none 似乎解决了我的问题。
我有一个 Window 这样的:
<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>
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); }
}
}
据我所知,我的 Window 现在应该有 2 个彼此绑定的 TextBox 控件。就像我改变其中一个的值一样,另一个应该更新。
但是,我最终得到了 2 个单独的文本框,其中第一个以文本 "Empty" 开头,下一个以文本 "Totally different value" 开头。像这样:
并且更改其中任何一个的文本不会在另一个中重现。
我希望它们都以文本 "Totally different value" 开始并与它们的值同步(通过传播对 MainWindow 上的 MyTextValue 属性 的更改,以及通过通知那里的更改,更改将传播到另一个文本框)。在我的控制中正确实施 data-binding 我缺少什么?
尝试更改此行:
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));
删除分配
DataContext="{Binding RelativeSource={RelativeSource Self}}"
来自 UserControl 的 XAML。相反,将 "internal" 绑定的 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。