【问题标题】:WPF databinding with a user control带有用户控件的 WPF 数据绑定
【发布时间】:2011-01-16 08:01:53
【问题描述】:

我有一个 wpf 用户控件,它公开了一个自定义依赖属性。在用户控件内部,一个文本块绑定到 dp 的值。此数据绑定适用于所有场景,但数据源是对象时除外。

重现此所需的最少代码是:

这是用户控件的主要部分

<StackPanel Orientation="Horizontal">
    <TextBlock Text="**SimpleUC** UCValue: "/>
    <TextBlock Text="{Binding UCValue}"/>
</StackPanel>

以及后面的用户控制代码:

    public SimpleUC()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    public string UCValue
    {
        get { return (string)GetValue(UCValueProperty); }
        set { SetValue(UCValueProperty, value); }
    }

    public static readonly DependencyProperty UCValueProperty =
        DependencyProperty.Register("UCValue", typeof(string), typeof(SimpleUC), new UIPropertyMetadata("value not set"));

这是测试窗口。我将我的项目 xml 命名空间导入为“自定义”

<Window.Resources>
    <Style TargetType="{x:Type StackPanel}">
        <Setter Property="Margin" Value="20"/>
    </Style>
</Window.Resources>
<StackPanel>
    <StackPanel>
        <TextBlock Text="This fails to bind:"/>
        <custom:SimpleUC UCValue="{Binding SomeData}"/> 
    </StackPanel>
    <StackPanel>
        <TextBlock>The same binding on a regular control like Label</TextBlock>
        <Label Content="{Binding SomeData}"/>
    </StackPanel>
    <Slider x:Name="sld" />
    <StackPanel>
        <TextBlock>However, binding the UC to another element value, like a slider works</TextBlock>
        <custom:SimpleUC UCValue="{Binding ElementName=sld,Path=Value}"/>
    </StackPanel>
</StackPanel>

而后面的测试窗口代码是:

public TestWindow()
{
    InitializeComponent();
    this.DataContext = this;
}

//property to bind to
public string SomeData { get { return "Hello S.O."; } } 

当我在 TestWindow 上打开诊断跟踪时,它会吐出错误“BindingExpression path error: 'SomeData' property not found on 'object' ''SimpleUC' (Name='')' ... "
绑定表达式与我在相邻标签中使用的相同,并且效果很好。这种行为对我来说真的很奇怪。有人能解释一下吗?

【问题讨论】:

    标签: wpf data-binding user-controls


    【解决方案1】:

    如果您必须使用UserControl,您的

    <TextBlock
      Text="{Binding RelativeSource={RelativeSource Self},
                     Path=Parent.Parent.UCValue}"
    />
    

    这是一个不错的方法,并且

    <TextBlock
      Text="{Binding UCValue,
                     RelativeSource={RelativeSource FindAncestor,custom:SimpleUC,1}}"
    />
    

    更好,因为您不依赖控制层次结构和可能的实例化顺序问题。

    但是,对于这种情况,我建议您使用“自定义控件”而不是“用户控件”。它们需要一点时间来适应,但它们更强大,因为它们的 XAML 本身就是模板,这意味着您可以使用 TemplateBinding{RelativeSource TemplatedParent}

    无论如何,DataContext = this; 是绝对要避免的。

    【讨论】:

      【解决方案2】:

      您在此处将 SimpleUC 的 DataContext 设置为自身

      public SimpleUC()
      {
          InitializeComponent();
          this.DataContext = this; // wrong way!
      }
      

      所以当你在这里使用绑定时

      <custom:SimpleUC UCValue="{Binding SomeData}"/>
      

      它在控件的数据上下文中搜索属性 SomeData ,该属性设置为此对象,因为 SimpleUC 构造函数中的代码覆盖了 DataContext 的值,并且它不再像您预期的那样设置为 TestWindow 对象。这就是您的解决方案有效的原因 - 它不会影响从 window.context 继承的 DataContext。您也可以保留this.DataContext = this;,但设置元素在哪里明确搜索属性(跳过无关)

      <Window ... Name="wnd1">
          <custom:SimpleUC UCValue="{Binding SomeData, ElementName=wnd1}"/>
      ...
      

      但我的意见是,您的答案变体对我来说看起来更方便,将数据上下文设置为 this 不是很好的做法。

      希望对你有帮助。

      【讨论】:

      • 感谢您解释为什么 DataContext=this 没有按预期工作。这真的让我陷入了循环。
      猜你喜欢
      • 2016-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-28
      • 1970-01-01
      相关资源
      最近更新 更多