绑定到 UserControl DependencyProperty
Posted
技术标签:
【中文标题】绑定到 UserControl DependencyProperty【英文标题】:Binding to UserControl DependencyProperty 【发布时间】:2013-06-03 20:04:16 【问题描述】:我创建了一个带有一些 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>
标签的行为是正确的,所以属性“文本”没有问题
我的错误是什么?我思考了好几个小时,但找不到我忘记的任何东西。
【问题讨论】:
【参考方案1】:在您的UserControl
中使用以下绑定:
<Label Content="Binding MyText"/>
我不确定如何将文本直接设置为 MyText 属性。您必须在 UserControl
上设置 DataContext
才能使其正常工作。
无论如何,此绑定是问题所在 - 据我了解您的情况,您不想绑定到 UserControl
的 DataContext
,因为它不一定具有 MyText 属性。您想绑定到 UserControl
本身,特别是您创建的 DependencyProperty
。为此,您需要使用RelativeSource
绑定,如下所示:
<Label Content="Binding RelativeSource=RelativeSource AncestorType=x:Type local:MyUserControl, Path=MyText"/>
这会将可视化树向上导航到 MyUserControl,然后在那里找到 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"
...>
此时您的第二个示例应该可以工作。
【讨论】:
@Brian... 代码“this.DataContext = this;”应该注意将 DataContext 设置为本地。不应该吗? 哦,是的,我错过了。但是,如果您要创建UserControl
,我认为手动设置DataContext
不是一个好主意。 DataContext
旨在表示从容器继承或分配的上下文。 RelativeSource
绑定允许您在不中断标准DataContext
继承流程的情况下实现所需的结果(绑定到DependencyProperty
)。如果您的UserControl
的使用者设置了自己的DataContext
,那么尝试覆盖DataContext
将会失败。
这正是问题所在。我现在在 MyUserControl
的开始标记中使用 x:Name="MyName"
而不是将 MyUserControl 的 DataContext 设置为自身,并且绑定更改为:<Label Content="Binding ElementName=MyName, Path=MyText"/>
我认为您的解决方案也应该可以工作,但它有点笨拙。
是的,使用ElementName
绑定将实现相同的结果,并且不那么冗长,特别是如果您确信其他人不会修改您的代码并错误地更改/删除名称。
这个答案与问题完全无关。我想知道为什么这会受到如此多的赞成甚至被接受。【参考方案2】:
对DataContext
s 的设置方式存在误解。这对你不利...
最终绑定到用户控件上的MyText
,未绑定到控件的MyText
依赖属性,而是到页面的DataContext
,并且没有MyText
属性。
让我解释一下
说明当用户控件放在您的主页上时,它会继承其控件父级的DataContext
(StackPanel
)。如果未设置父级的DataContext
,它将向上移动到StackPanel
的父级DataContext
(ad Infinium),直到到达页面的DataContext
(在您的示例中设置并且有效)。
当您在主页面(例如<local:MyUserControl MyText="Binding Path=Text"/>
)上绑定时,它会在主页面DataContext 上查找Text
属性并将依赖属性MyText
设置为该值。 这是你所期望的,它有效!
当前状态
所以代码中用户控件的状态是这样的,它的DataContext
绑定到页面的DataContext
并且设置了MyText
依赖属性。 但是内部控制绑定到MyText
失败。 为什么?
用户控件具有父级的数据上下文,并且您要求控件绑定到 那个 数据上下文上的MyText
属性。没有这样的属性,它失败了。
分辨率
要绑定到控件的instance并从MyText
属性中获取值,只需在控件上放一个名称(元素名称),例如
<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 粘贴到页面上。
【讨论】:
您混淆了控件及其数据上下文。你应该改写你的帖子来解决这个困惑。以上是关于绑定到 UserControl DependencyProperty的主要内容,如果未能解决你的问题,请参考以下文章
绑定到 UserControl 中声明的 Storyboard 的属性