我不确定我在这里做错了什么。
让我们说,我有两个UserControl BoxA
和BoxB
。两者都有一个名为Text
BoxB包装BoxA,它有一个常规的TextBox。
绑定应该像这个BoxB.Text< =>一样工作BoxA.Text< => TextBox.Text
Xaml BoxA:
<UserControl x:Class="SandBoxWpf.BoxA"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></TextBox>
</UserControl>
Xaml BoxB:
<UserControl x:Class="SandBoxWpf.BoxB"
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:SandBoxWpf"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<local:BoxA Text="{Binding Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></local:BoxA>
</UserControl>
BoxA和BoxB的代码隐藏
using System.Windows;
using System.Windows.Controls;
namespace SandBoxWpf
{
/// <summary>
/// Interaktionslogik für BoxA.xaml
/// </summary>
public partial class BoxX : UserControl
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(BoxX),
new PropertyMetadata(default(string)));
public string Text
{
get => (string) GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public BoxX()
{
InitializeComponent();
}
}
}
主窗口
<Window x:Class="SandBoxWpf.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:SandBoxWpf"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<local:BoxB Width="100" Height="20" Text="{Binding Title}"></local:BoxB>
</Grid>
</Window>
只要我在BoxB中输入内容,我就会收到StackoverflowException。 如果我删除了Mode = TwoWay或UpdateSourceTrigger,StackOverflow就消失了,但绑定也不起作用。
答案 0 :(得分:4)
如果要构建具有可绑定属性的UserControl(即依赖项属性),则必须在任何情况下都无法显式设置UserControl的DataContext ,无论是控件实例还是任何私有视图模型。 / p>
如果你这样做,就像
这样的绑定<local:BoxB Text="{Binding Title}">
将不再有效。 Binding期望当前DataContext中对象的Title属性。 DataContext属性值通常从UserControl的父元素继承,例如,窗户。但是,由于您已明确设置DataContext,因此可以避免使用此机制。
这对于UserControls中同名的属性尤其令人困惑。当你写
<local:BoxA Text="{Binding Text, ...}"/>
在UserControl BoxB中,您的期望是绑定源属性为BoxB.Text
。实际上它是BoxA.Text
,因为BoxA的DataContext是BoxA实例。
所以删除任何
DataContext="{Binding RelativeSource={RelativeSource Self}}"
行并使用RelativeSource在UserControl的XAML中编写Bindings,如下所示:
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay},
RelativeSource={RelativeSource AncestorType=UserControl}"/>
<local:BoxA Text="{Binding Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay},
RelativeSource={RelativeSource AncestorType=UserControl}"/>
答案 1 :(得分:-1)
对于任何形式的变更通知,一个危险就是我称之为“乒乓”的问题。例如:
为了避免这种情况,Properties with Change notificaiton的示例代码如下所示:
public string PhoneNumber
{
get
{
return this.phoneNumberValue;
}
set
{
if (value != this.phoneNumberValue)
{
this.phoneNumberValue = value;
NotifyPropertyChanged();
}
}
}
如果输入与输出相同,则不执行任何操作。结果如下:
我最好的猜测是WPF Elements没有这样的保护。其中一个案例是“试图变得聪明可能会导致真正的愚蠢”。