WPF 用户控件中的数据绑定
Posted
技术标签:
【中文标题】WPF 用户控件中的数据绑定【英文标题】:Data Binding in WPF User Controls 【发布时间】:2022-01-05 22:42:54 【问题描述】:我正在为多个窗口共享的一系列控件创建一个 UserControl。其中一个控件是一个标签,它以“协议号”的形式显示其他一些流程的流程。
我正在尝试使用此标签提供 DataBinding,以便窗口在协议编号变量更改时自动反映进程的状态。
这是用户控件 XAML:
<UserControl Name="MainOptionsPanel"
x:Class="ExperienceMainControls.MainControls"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="Binding RelativeSource=RelativeSource Self"
>
<Label Height="Auto" Name="numberLabel">Protocol:</Label>
<Label Content="Binding Path=ProtocolNumber" Name="protocolNumberLabel"/>
(...)
</UserControl>
这是代码隐藏:
public partial class MainControls
public MainControls()
InitializeComponent();
public int ProtocolNumber
get return (int)GetValue(ProtocolNumberProperty);
set SetValue(ProtocolNumberProperty, value);
public static DependencyProperty ProtocolNumberProperty =
DependencyProperty.Register("ProtocolNumber", typeof(int), typeof(MainControls));
这似乎有效,因为如果我在构造函数中将 ProtocolNumber 设置为任意值,它会反映在用户控件中。
但是,当在最终窗口上使用此用户控件时,数据绑定会中断。
XAML:
<Window x:Class="UserControlTesting.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:expControl="clr-namespace:ExperienceMainControls;assembly=ExperienceMainControls"
DataContext="Binding RelativeSource=RelativeSource Self"
>
<StackPanel>
<expControl:MainControls ProtocolNumber="Binding Path=Number, Mode=TwoWay" />
</StackPanel>
</Window>
窗口的代码隐藏:
public partial class Window1 : Window
public Window1()
Number= 15;
InitializeComponent();
public int Number get; set;
这会将协议编号设置为零,忽略设置为编号的值。
我读过例子
【问题讨论】:
在您的输出窗口中,您将看到一个绑定错误,例如对象 MainOptionsPanel 没有属性编号 - 这是真的。只需将您的用户控件 xaml 更改为我的答案。 【参考方案1】:如果您查看输出窗口,您应该会看到绑定异常。
您遇到的问题如下:在您的用户控件中,您会将标签绑定到您的用户控件的 DP ProtocolNumber 而不是DataContext
,因此您必须将元素名称添加到绑定中。
<UserControl Name="MainOptionsPanel"
x:Class="ExperienceMainControls.MainControls"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="uc"
>
<Label Height="Auto" Name="numberLabel">Protocol:</Label>
<Label Content="Binding Path=ProtocolNumber, ElementName=uc" Name="protocolNumberLabel"/>
(...)
</UserControl>
编辑:为了清除一些事情,如果您更改 MainWindow 中的绑定,您的用户控件也可以工作。但是您必须使用 RelativeSource 绑定到 MainWindow 的 DataContext。
<expControl:MainControls ProtocolNumber="Binding Path=Number, RelativeSource=RelativeSource AncestorType=x:Type Window" />
【讨论】:
【参考方案2】:如果您没有指定绑定的RelativeSource
,请尝试在构造函数中设置DataContext
:
public Window1()
Number= 15;
DataContext = this;
InitializeComponent();
【讨论】:
说实话,这种方法很糟糕,因为您可以从外部更改数据上下文。【参考方案3】:你有什么效果:
<expControl:MainControls DataContext="Binding RelativeSource=RelativeSource Self"
ProtocolNumber="Binding Path=Number, Mode=TwoWay"/>
=> 不要不要在UserControl
声明中设置DataContext
,而是使用RelativeSource
或ElementName
绑定。
【讨论】:
为什么不设置DataContext?我知道它可以通过多种方式传播到子控件(我认为),但到目前为止,我们的应用程序还没有遇到任何问题。 @mizipzor:这是不好的做法,像这样设置 DataContext 是“从外部”不可见的,并且不切实际,因为 DataContext 的继承通常是您想要和期望的。 实际上,DataContext 的继承(到目前为止)不是我想要的。 CustomControls 是另一回事。但对于 UserControls,我认为它是一种很好的做法。 那么您的意思是从 Usercontrol 定义中删除 DataContext 行?因为在那里我也将它定义为RelativeSource。 @kelmer:是的。它不是同一个对象,您在定义中所做的任何事情都适用于您的实例,在设置 DataContext 的情况下,正如您刚刚展示的那样,这是一个坏主意,因为它会覆盖继承的 DataContext。以上是关于WPF 用户控件中的数据绑定的主要内容,如果未能解决你的问题,请参考以下文章