【问题标题】:Data Binding in WPF User ControlsWPF 用户控件中的数据绑定
【发布时间】:2012-06-28 22:08:27
【问题描述】:

我正在为多个窗口共享的一系列控件创建一个 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; }
}

这会将协议编号设置为零,忽略设置为 Number 的值。

我读过例子

【问题讨论】:

  • 在您的输出窗口中,您将看到一个绑定错误,例如对象 MainOptionsPanel 没有属性编号 - 这是真的。只需将您的用户控件 xaml 更改为我的答案。

标签: c# wpf xaml data-binding user-controls


【解决方案1】:

如果您没有指定绑定的RelativeSource,请尝试在构造函数中设置DataContext

    public Window1()
    {
        Number= 15;
        DataContext = this;
        InitializeComponent();
    }

【讨论】:

  • 说实话,这种方法很糟糕,因为您可以从外部更改数据上下文。
【解决方案2】:

你有什么效果:

<expControl:MainControls DataContext="{Binding RelativeSource={RelativeSource Self}}"
                         ProtocolNumber="{Binding Path=Number, Mode=TwoWay}"/>

=> 不要不要UserControl 声明中设置DataContext,而是使用RelativeSourceElementName 绑定。

【讨论】:

  • 为什么不设置DataContext?我知道它可以通过多种方式传播到子控件(我认为),但到目前为止,我们的应用程序还没有遇到任何问题。
  • @mizipzor:这是不好的做法,像这样设置 DataContext 是“从外部”不可见的,并且不切实际,因为 DataContext 的继承通常是您想要和期望的。
  • 实际上,DataContext 的继承(到目前为止)不是我想要的。 CustomControls 是另一回事。但对于 UserControls,我认为它是一种很好的做法。
  • 那么您的意思是从 Usercontrol 定义中删除 DataContext 行?因为在那里我也将它定义为RelativeSource。
  • @kelmer:是的。它不是同一个对象,您在定义中所做的任何事情都适用于您的实例,在设置 DataContext 的情况下,正如您刚刚展示的那样,这是一个坏主意,因为它会覆盖继承的 DataContext。
【解决方案3】:

如果您查看输出窗口,您应该会看到绑定异常。

您遇到的问题如下:在您的用户控件中,您会将标签绑定到您的用户控件的 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}}}" />

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    相关资源
    最近更新 更多