wpf 绑定到 UserControl DependencyProperty

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16985382/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:57:24  来源:igfitidea点击:

Binding to UserControl DependencyProperty

c#wpfbindinguser-controlsdependency-properties

提问by Buchter

I have created a UserControl with some DependencyProperties (in the example here only one string property). When I instantiate the Usercontrol, I can set the property of the UserControl and it is shown as expected. When I am trying to replace the static text by Binding, nothing is displayed.

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

My UserControl looks as follows:

我的用户控件如下所示:

<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>

The Code Behind is:

背后的代码是:

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

  }
}

When I try this in my MainWindow, everything is as expected:

当我在 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>

But this doesn't work:

但这不起作用:

<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>

The behaviour of the label is correct, so there is no Problem with the Property "Text"

标签的行为是正确的,所以属性“文本”没有问题

What is my mistake? I Ponder for hours, but can't find anything I have forgotten.

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

回答by Brian S

With the following binding in your UserControl:

在您的以下绑定中UserControl

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

I'm not sure how setting the text directly to the MyText property works. You must be setting the DataContexton the UserControlsomewhere for this to work.

我不确定将文本直接设置为 MyText 属性是如何工作的。你必须DataContextUserControl某个地方设置它才能工作。

Regardless, this binding is the issue - as I understand your scenario, you don't want to bind to the DataContextof the UserControlbecause that will not necessarily have a MyText property. You want to bind to the UserControlitself, and specifically the DependencyPropertyyou created. To do that, you need to use a RelativeSourcebinding, like the following:

无论如何,此绑定是问题-据我了解您的情况,您不想绑定到DataContextUserControl因为它不一定具有 MyText 属性。你想绑定到它UserControl本身,特别是DependencyProperty你创建的。为此,您需要使用RelativeSource绑定,如下所示:

<Label Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MyUserControl}}, Path=MyText}"/>

This will navigate up the visual tree to MyUserControl and then find the MyText property there. It will not be dependent on the DataContext, which will change based on where you place the UserControl.

这将在可视树中向上导航到 MyUserControl,然后在那里找到 MyText 属性。它不会依赖于DataContext,这将根据您放置UserControl.

In this case, localrefers to a namespace you'll need to define in the 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"
         ...>

And your second example should work at that point.

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

回答by ΩmegaMan

There is a misunderstanding of how DataContexts are set. This is working against you...

DataContexts 的设置方式存在误解。这对你不利...

Ultimately the binding to MyTexton the user control, is not boundto the control's MyTextdependency property but to the page's DataContextand there is no MyTextproperty.

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

Let me explain

让我解释



ExplanationWhen the user control is put on your main page, it inherits its controls parent's DataContext(the StackPanel). If the parent's DataContextis not set, it will move up the chain to the StackPanel's parent's DataContext(ad Infinium) until it gets to the page's DataContext(which in your example is set and valid).

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

When you bind on the main page such as <local:MyUserControl MyText="{Binding Path=Text}"/>it looks for Textproperty on the main pages DataContext and sets the dependency property MyTextto that value. Which is what you expect and it works!

当您在主页上绑定时,例如<local:MyUserControl MyText="{Binding Path=Text}"/>Text在主页 DataContext 上查找属性并将依赖属性MyText设置为该值。这就是您所期望的,并且有效!

Current StateSo the state of the user control in your code is this, its DataContextis bound to the page's DataContextand MyTextdependency property is set. Butthe internal control's binding to MyTextfails. Why?

当前状态所以你的代码中用户控件的状态是这样的,它DataContext被绑定到页面的DataContext并且MyText依赖属性被设置。内部控制的约束MyText失效。为什么?

The user control has the parent's data context, and you are asking the control to bind to a MyTextproperty on thatdata context. There is no such property and it fails.

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



Resolution

解析度

To bind to the control's instanceand get the value from MyTextproperty, just put a name (an element name) on the control such as

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

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

and then properly path the binding away from the default DataContextand to the elementnamednamed instance called ucMyUserControl. Such as:

然后正确路径从默认绑定离开DataContext并到elementnamed称为命名实例ucMyUserControl。如:

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

Note that VS2017/2019 will actually intellisense the ElementNameafter you have named the control.

请注意,VS2017/2019 实际上会ElementName在您为控件命名后进行智能感知。



Side Effect of Just Using The Parents Data Context

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

A side effect of the original situation without the resolution mentioned, is that you could just bind the user control's binding to Textand it will workbecause the binding is defaulting to the page's datacontext. Subtle...

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

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

That works and technically you could remove the dependency property. If the control is not used outside the project, it could be designed to bind to other named properties with no ill effect as well.

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

Then all usercontrols could become defacto sub controls of the main page, as ifyou just pasted the internal XAML onto the page.

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