Buc*_*ter 12 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>
Run Code Online (Sandbox Code Playgroud)
守则背后是:
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
}
}
Run Code Online (Sandbox Code Playgroud)
当我在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>
Run Code Online (Sandbox Code Playgroud)
但这不起作用:
<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>
Run Code Online (Sandbox Code Playgroud)
标签的行为是正确的,因此属性"文本"没有问题
我的错是什么?我思考了几个小时,但找不到任何我忘记的东西.
Bri*_*n S 15
使用以下绑定UserControl:
<Label Content="{Binding MyText}"/>
Run Code Online (Sandbox Code Playgroud)
我不确定如何直接将文本设置为MyText属性.你必须DataContext在UserControl某个地方设置它才能工作.
无论如何,这个绑定是问题 - 因为我理解你的场景,你不想绑定到它DataContext,UserControl因为它不一定有MyText属性.您想要绑定到UserControl自身,特别是DependencyProperty您创建的.为此,您需要使用RelativeSource绑定,如下所示:
<Label Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MyUserControl}}, Path=MyText}"/>
Run Code Online (Sandbox Code Playgroud)
这将向上导航可视树到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"
...>
Run Code Online (Sandbox Code Playgroud)
你的第二个例子应该在那一点上起作用.
DataContext对s 的设置方式存在误解。这对你不利......
MyText最终,对用户控件的绑定不是绑定到控件的MyText依赖属性,而是绑定到页面的依赖属性DataContext,并且没有MyText属性。
让我解释
说明当用户控件放置在主页上时,它会继承其父级控件DataContext(StackPanel)。DataContext如果未设置父级,它将沿着链向上移动到StackPanel父级DataContext(无限),直到到达页面DataContext(在您的示例中已设置且有效)。
当您在主页上绑定时,例如它会在主页 DataContext 上<local:MyUserControl MyText="{Binding Path=Text}"/>查找属性并将依赖属性设置为该值。这就是您所期望的并且它有效!TextMyText
当前状态
因此代码中用户控件的状态是这样的,它DataContext绑定到页面DataContext并且MyText设置了依赖属性。但内部控制绑定MyText失败。为什么?
用户控件具有父级的数据上下文,并且您要求控件绑定到该MyText数据上下文上的属性。不存在这样的属性并且它失败了。
解决
要绑定到控件的实例并从属性中获取值MyText,只需在控件上放置一个名称(元素名称),例如
<User Control x:Class="TestUserControBinding.MyUserControl"
...
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
x:Name="ucMyUserControl"
Run Code Online (Sandbox Code Playgroud)
然后正确地将绑定从默认路径转移DataContext到名为 的elementnamed命名实例ucMyUserControl。例如:
<Label Content="{Binding MyText, ElementName=ucMyUserControl }"/>
Run Code Online (Sandbox Code Playgroud)
请注意,VS2017/2019 实际上会ElementName在您命名控件后进行智能感知。
仅使用父母数据上下文的副作用
没有提到的解决方案的原始情况的副作用是,您只需将用户控件的绑定绑定到Text它就会起作用,因为绑定默认为页面的数据上下文。微妙的...
<User Control x:Class="TestUserControBinding.MyUserControl"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="100">
<Grid>
<Label Content="{Binding Text}"/>
Run Code Online (Sandbox Code Playgroud)
这可行,从技术上讲,您可以删除依赖属性。如果该控件不在项目外部使用,则可以将其设计为绑定到其他命名属性,也不会产生不良影响。
然后,所有用户控件都可以成为主页的事实上的子控件,就好像您刚刚将内部 XAML 粘贴到页面上一样。