绑定到UserControl DependencyProperty

时间:2013-06-07 13:30:16

标签: c# wpf binding user-controls dependency-properties

我创建了一个带有一些DependencyProperties的UserControl(在这个例子中只有一个字符串属性)。当我实例化Usercontrol时,我可以设置UserControl的属性,并按预期显示。当我尝试通过Binding替换静态文本时,不会显示任何内容。

我的UserControl如下所示:

<User Control x:Class="TestUserControBinding.MyUserControl"
             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="30" d:DesignWidth="100">
    <Grid>
    <Label Content="{Binding MyText}"/>
  </Grid>
</UserControl>

守则背后是:

namespace TestUserControBinding {

  public partial class MyUserControl : UserControl {
    public MyUserControl() {
      InitializeComponent();
      this.DataContext = this;
    }

    public static readonly DependencyProperty MyTextProperty = 
                   DependencyProperty.Register(
                         "MyText", 
                          typeof(string), 
                          typeof(MyUserControl));

    public string MyText {
      get {
        return (string)GetValue(MyTextProperty);
      }
      set {
        SetValue(MyTextProperty, value);
      }
    }// MyText

  }
}

当我在MainWindow中尝试这个时,一切都如预期的那样:

<Window x:Class="TestUserControBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestUserControBinding"
        Title="MainWindow" Height="350" Width="525">
  <StackPanel>
    <local:MyUserControl MyText="Hello World!"/>
  </StackPanel>
</Window>

但这不起作用:

<Window x:Class="TestUserControBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestUserControBinding"
        Title="MainWindow" Height="350" Width="525">
  <StackPanel>
    <local:MyUserControl MyText="{Binding Path=Text}"/>
    <Label Content="{Binding Path=Text}"/>
  </StackPanel>
</Window>

标签的行为是正确的,因此“Text”属性没有问题

我的错误是什么?我思考了几个小时,但找不到任何我忘记的东西。

2 个答案:

答案 0 :(得分:14)

UserControl中使用以下绑定:

<Label Content="{Binding MyText}"/>

我不确定如何直接将文本设置为MyText属性。您必须在DataContext某处设置UserControl才能使其生效。

无论如何,这个绑定是问题 - 因为我理解你的场景,你不想绑定到DataContext的{​​{1}},因为它不一定具有MyText属性。您想要绑定到UserControl本身,特别是您创建的UserControl。为此,您需要使用DependencyProperty绑定,如下所示:

RelativeSource

这会将可视化树导航到MyUserControl,然后在那里找到MyText属性。它不依赖于<Label Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MyUserControl}}, Path=MyText}"/> DataContext会根据您放置UserControl的位置而改变。

在这种情况下,local指的是您需要在UserControl中定义的命名空间:

<UserControl x:Class="TestUserControBinding.MyUserControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:TestUserControBinding"
         ...>

你的第二个例子应该在那时起作用。

答案 1 :(得分:0)

DataContext的设置方式有误解。这对你不利...

最终,与用户控件上的MyText的绑定未未绑定到控件的MyText的依赖项属性,而是被绑定到页面的DataContext,并且没有MyText属性。

让我解释一下


说明:将用户控件放在您的主页上时,它将继承其控件父级的DataContextStackPanel)。如果未设置父级的DataContext,它将向上移动到StackPanel父级的DataContext(在Infinium中),直到到达页面的DataContext(< em>在您的示例中已设置且有效)。

在诸如<local:MyUserControl MyText="{Binding Path=Text}"/>之类的主页上进行绑定时,它将在主页DataContext上寻找Text属性,并将依赖项属性MyText设置为该值。 您期望的是什么,它会起作用!

当前状态 因此,您的代码中用户控件的状态是这样,其DataContext绑定到页面的DataContext并设置了MyText依赖项属性。 但是,内部控制与MyText的绑定失败。 为什么?

用户控件具有父级的数据上下文,并且您要控件绑定到那个数据上下文上的MyText属性。没有这样的属性,它将失败。


解决方案

要绑定到控件的实例并从MyText属性获取值,只需在控件上放置一个名称(元素名称),例如< / p>

<User Control x:Class="TestUserControBinding.MyUserControl"
             ...
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             x:Name="ucMyUserControl"

,然后正确地将绑定从默认的DataContext转移到名为ucMyUserControl elementnamed 命名实例。如:

  <Label Content="{Binding MyText, ElementName=ucMyUserControl }"/>

请注意,在将控件命名后,VS2017 / 2019实际上会智能感知ElementName


仅使用父母数据上下文的副作用

没有提到解决方案的原始情况的副作用是,您可以将用户控件的绑定仅绑定到Text,它将起作用,因为该绑定默认为页面的数据上下文。 微妙...

<User Control x:Class="TestUserControBinding.MyUserControl"
             mc:Ignorable="d" 
             d:DesignHeight="30" d:DesignWidth="100">
 <Grid>
    <Label Content="{Binding Text}"/>

可行,从技术上讲,您可以删除依赖项属性。如果未在项目外部使用控件,则可以将其设计为绑定到其他命名属性,而不会产生不良影响。

然后所有用户控件都可能成为主页上的事实上的子控件,就像您刚刚将内部XAML粘贴到页面上一样。