wpf 将依赖属性绑定到当前 DataContext 属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15883637/
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
Binding Dependency Property to Current DataContext Property
提问by imdandman
I keep trying to make this hurdle in WPF, and I think I've found a solution, albeit an ugly one.
我一直试图在 WPF 中克服这个障碍,我想我已经找到了一个解决方案,尽管是一个丑陋的解决方案。
The scenario is as follows:
场景如下:
- I have a custom user control with a custom dependency property.
- The user controls can be nested inside of my other user controls.
- Each of my user controls has a data context that is specified by a locator (I am following the MVVM pattern)
- I want to bind the custom dependency property to a value in the parent view model.
- 我有一个带有自定义依赖项属性的自定义用户控件。
- 用户控件可以嵌套在我的其他用户控件中。
- 我的每个用户控件都有一个由定位器指定的数据上下文(我遵循 MVVM 模式)
- 我想将自定义依赖属性绑定到父视图模型中的值。
Code...
代码...
Parent View
父视图
<UserControl DataContext="{Binding Source={StaticResource Locator}, Path=ParentControlLocator}">
<my:Child Demo="{Binding Path=DataContext.DemoTextAlpha, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl, AncestorLevel=1}}" />
</UserControl>
Parent Class View Model
父类视图模型
public class ParentClassViewModel : BaseViewModel
{
private string _demoTextAlpha = "Some Alpha text";
public string DemoTextAlpha
{
get
{
return this._demoTextAlpha;
}
set
{
this._demoTextAlpha = value;
this.NotifyPropertyChange("DemoTextAlpha");
}
}
}
Child View
子视图
<UserControl DataContext="{Binding Source={StaticResource Locator}, Path=ChildControlLocator}">
<TextBlock Text="{Binding Path=SomeProperty}" />
</UserControl>
Child View Code Behind
子视图背后的代码
public partial class Child : UserControl
{
public Child()
{
InitializeComponent();
}
public static readonly DependencyProperty DemoProperty =
DependencyProperty.Register("Demo",
typeof(string),
typeof(Child),
new FrameworkPropertyMetadata()
{
PropertyChangedCallback = OnDemoChanged,
BindsTwoWayByDefault = true
});
public string Demo
{
get { return this.GetValue(DemoProperty).ToString(); }
set { this.SetValue(DemoProperty, value); }
}
private static void OnDemoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (Child)d;
var viewModel = (ChildViewModel)control.DataContext;
viewModel.SomeProperty = (string)e.NewValue;
}
}
Child View Model
子视图模型
public class ChildViewModel : BaseViewModel
{
private string _someProperty;
public string SomeProperty
{
get
{
return _someProperty;
}
set
{
_someProperty = value;
this.NotifyPropertyChange("SomeProperty");
}
}
}
Ok, so this WORKS. What I'm trying to achieve is better/ more elegant code, particularly as it regards to this statement.
好了,这个作品。我想要实现的是更好/更优雅的代码,尤其是在这句话方面。
<my:Child Demo="{Binding Path=DataContext.DemoTextAlpha, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl, AncestorLevel=1}}" />
Even that I could live with, as far as elegance goes, but one thing that is bothering me right now is that when I type
就优雅而言,即使我可以忍受,但现在困扰我的一件事是当我打字时
Path=DataContext.DemoTextAlpha
The intellisense drops when I try to drill down inside the DataContext. So I have to be extra careful to type everything right.
当我尝试在 DataContext 中向下钻取时,智能感知下降。因此,我必须格外小心地正确输入所有内容。
So - is there any different way to make the properties of the DataContext appear in intellisense, or is there an alternative way to achieve the same thing that I'm doing now?
那么 - 是否有任何不同的方法可以使 DataContext 的属性出现在智能感知中,或者是否有另一种方法来实现我现在正在做的事情?
Thanks.
谢谢。
EDIT to Clarify
编辑以澄清
When I put something like this instead of specifying the relative source as in the above examples...
当我把这样的东西而不是在上面的例子中指定相对来源时......
<my:Child Demo="{Binding DemoTextAlpha}"/>
I receive an error...
我收到一个错误...
System.Windows.Data Error: 40 : BindingExpression path error: 'DemoTextAlpha' property not found on 'object' ''ChildViewModel' (HashCode=34126977)'. BindingExpression:Path=DemoTextAlpha; DataItem='ChildViewModel' (HashCode=34126977); target element is 'Child' (Name=''); target property is 'Demo' (type 'String')
回答by Federico Berasategui
The DataContext(along with a lot of other properties such as FontSize) is "Inherited"along the visual tree. Therefore this:
的DataContext(与很多其它性能如沿FontSize)的“继承”沿着视觉树。因此这个:
<UserControl DataContext="{Binding Source={StaticResource Locator}, Path=ParentControlLocator}">
<my:Child Demo="{Binding Path=DataContext.DemoTextAlpha, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl, AncestorLevel=1}}" />
</UserControl>
Is exactly the same as this:
和这个完全一样:
<UserControl DataContext="{Binding Source={StaticResource Locator}, Path=ParentControlLocator}">
<my:Child Demo="{Binding DemoTextAlpha}"/>
</UserControl>
With regards to the Intellisense support, I don't know what VS version you're using, but I'm using VS 2010 Pro with ReSharper 6.1 and it adds Intellisense support if you specify the d:DataContextvalue:
关于 Intellisense 支持,我不知道您使用的是哪个 VS 版本,但我使用的是 VS 2010 Pro 和 ReSharper 6.1,如果您指定d:DataContext值,它会添加 Intellisense 支持:
<UserControl x:Class="...etc."
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TheViewModelNamespace"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DataContext="{d:DesignInstance local:ViewModel}">
Edit:
编辑:
Ok.. let's analize what you're doing here:
好的..让我们分析一下你在这里做什么:
1- Binding the UserControl to the ParentVM:
1- 将 UserControl 绑定到 ParentVM:
ParentVM -> UserControl
2- Using RelativeSource To Grab some property from ParentVM and place it into a Custom DP you created in the Child control
2- 使用 RelativeSource 从 ParentVM 获取一些属性并将其放入您在 Child 控件中创建的自定义 DP
ParentVM -> UserControl -> Child Control
3- In the OnPropertyChanged of the custom DP, setting that same value to the ChildVM
3- 在自定义 DP 的 OnPropertyChanged 中,为 ChildVM 设置相同的值
ParentVM -> UserControl -> Child Control -> ChildVM
Do you realize you're using the View (User Control, Child Control) as an intermediate to share some properties between 2 View Models? Why don't you just
您是否意识到您正在使用视图(用户控件、子控件)作为在 2 个视图模型之间共享某些属性的中间件?你为什么不只是
ParentVM -> ChildVM
Which would be easier, cleaner and really MVVM?
哪个更容易,更干净,真正的 MVVM?
Either put a reference from the ParentVM directly to the ChildVM, or use something like a Messengerpattern to have indirect communication between them.
要么将 ParentVM 的引用直接放入 ChildVM,要么使用类似Messenger模式的东西在它们之间进行间接通信。
回答by Marc
DataContext is inherited:
DataContext 被继承:
<UserControl DataContext="{Binding Source={StaticResource Locator}, Path=ParentControlLocator}">
<my:Child Demo="{Binding DemoTextAlpha}" />
</UserControl>
If, ina different scenario, your child control has a different DataContext specified and you still need to bind to a property of your parent control's DataContext, using ElementNameis probably nicer:
如果在不同的情况下,您的子控件指定了不同的 DataContext 并且您仍然需要绑定到父控件的 属性DataContext,则使用ElementName可能更好:
<UserControl x:Name="Parent" DataContext="{Binding Source={StaticResource Locator}, Path=ParentControlLocator}">
<my:Child Demo="{Binding Path=DataContext.DemoTextAlpha, ElementName=Parent}" />
</UserControl>

