如何创建“正常”绑定的 UserControl?
我会解释我的意思。
假设我将 TextBox 包装到 UserControl 中并公开属性 Id 为了绑定到此属性,它必须是依赖属性。好吧,我们开始吧(注意 OnIdChanged 调用属性设置器的愚蠢舞蹈,以便我们让 INotifyPropertyChanged 工作):
public static readonly DependencyProperty IdProperty =
DependencyProperty.RegisterAttached("Id", typeof(string), typeof(MyTextBox), new PropertyMetadata(OnIdChanged));
public string Id
{
get
{
return (string)GetValue(IdProperty);
}
set
{
this.SetValue(IdProperty, value);
this.OnPropertyChanged("Id");
}
}
private static void OnIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as Lookup).Id = e.NewValue as string;
}
所以,这似乎是我所需要的。我创建另一个用户控件。将 MyTextBox 放在上面:
<Lookup:MyTextBox Id="{Binding Source={StaticResource DataContextProxy}, Path=DataSource.CurrentItem.DeviceId, Mode=TwoWay, NotifyOnValidationError=True}"/>
如您所见 - 我必须使用 DataContextProxy。老实说,这对我来说有点神奇,我曾经做过一次,现在当常规方式不具有约束力时尝试一下。我应该如何编码我的用户控件,以便我可以像这样绑定到它?
<Lookup:MyTextBox Id="{Binding Path=CurrentItem.DeviceId, Mode=TwoWay, NotifyOnValidationError=True}"/>
这就是我如何将 TextBox 绑定到我的自定义文本框旁边,并且它按预期工作。秘密是什么?
编辑
下面是 2 个屏幕截图。第一个显示了当我绑定到 Lookup 控件(自定义 UserControl)时我如何获得作为源的内容 - 指向 SELF
第二个 - 我的 XAML 中的下一个字段 - 是常规文本框,绑定到相同的 CurrentItem 但它来自我的 ViewModel
编辑 2
我想通了为什么 DataContext 指向 UserControl 本身。我想为什么,但不明白为什么......
在初始化后后面的 UserControl(查找)代码中,我设置了 this.DataContext = this ,以便在控件内部它绑定到内部属性。它以某种方式传播到父 ViewModel。我将此代码更改为 LayoutRoot.DataContext = this 后 - 问题解决了。但我不明白为什么它会这样,而且我仍然无法获得良好的属性路由。
I will explain what I mean.
Let's say I wrapped TextBox into UserControl and expose property Id
In order to bind to this property, it has to be Dependency property. Fine, here we go(notice stupid dance with OnIdChanged calls property setter so we get INotifyPropertyChanged working):
public static readonly DependencyProperty IdProperty =
DependencyProperty.RegisterAttached("Id", typeof(string), typeof(MyTextBox), new PropertyMetadata(OnIdChanged));
public string Id
{
get
{
return (string)GetValue(IdProperty);
}
set
{
this.SetValue(IdProperty, value);
this.OnPropertyChanged("Id");
}
}
private static void OnIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as Lookup).Id = e.NewValue as string;
}
So, this seems like all I need. I create another User control. Drop MyTextBox on it:
<Lookup:MyTextBox Id="{Binding Source={StaticResource DataContextProxy}, Path=DataSource.CurrentItem.DeviceId, Mode=TwoWay, NotifyOnValidationError=True}"/>
As you see - I had to use DataContextProxy. To be honest, it's little bit of magic for me, I did it once and tried it now when regular way wasn't binding. How should I code my user control so I can bind to it like so?
<Lookup:MyTextBox Id="{Binding Path=CurrentItem.DeviceId, Mode=TwoWay, NotifyOnValidationError=True}"/>
This is how I can bind TextBox next to my custom one and it works as expected. What is the secret?
EDIT
Below is 2 screenshots. First one shows how what I get as a source when I bind to Lookup control (custom UserControl) - points to SELF
Second one - next field in my XAML - is regular textbox, binds to same CurrentItem but it sources from my ViewModel
EDIT 2
I figured why DataContext was pointing to UserControl itself. I figured why but do not understand why..
In my UserControl (Lookup) code behind after initializiation I set this.DataContext = this so inside control it binds to internal properties. Somehow it propogated to parent ViewModel. After I changed this code to LayoutRoot.DataContext = this - issue resolved. But I don't understand why it behaves like this and I still can't get good property routing through..
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我在一篇博客文章中介绍了这个问题,我前段时间写的。如果将 UserControl 的 DataContext 设置为其自身,则不能再将其放置在另一个 UserControl 或 Window 中并期望它继承其父级的 DataContext。这意味着您不能只是将其放在视图中并指定与视图模型的绑定。原因是您阻止了 ViewModel DataContext 的继承。 UserControl 公开的任何属性都将其绑定源设置为 UserControl。
解决方案是将 UserControl 内的某些元素的 DataContext 设置为 UserControl 本身。最典型的是,您将设置 UserControl 的直接子级。
I covered this issue in a blog post which I wrote some time ago. If you set the DataContext of the UserControl to itself, you can no longer place it within another UserControl or Window and expect it to inherit the DataContext of its parent. This means that you cannot just sit it in your view and specify bindings to your view model. The reasons for this is that you have blocked inheritence of your ViewModel DataContext. Any properties exposed by your UserControl will have their binding Source set to the UserControl.
The solution is to set DataContext of some element within the UserControl to the UserControl itself. Most typically you would set the immediate child of the UserControl.