C# 为什么绑定到用户控件上的DependencyProperty会使用用户控件';什么是数据上下文?

C# 为什么绑定到用户控件上的DependencyProperty会使用用户控件';什么是数据上下文?,c#,.net,wpf,binding,C#,.net,Wpf,Binding,假设我有一个WPF应用程序(exe),它在MainWindow.xaml中包含以下内容: <Grid> <extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}"/> <extraControls:MyUserControl MyDependencyProperty="{Binding Something}" /> </Grid> 我的Ma

假设我有一个WPF应用程序(exe),它在MainWindow.xaml中包含以下内容:

<Grid>
    <extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}"/>
    <extraControls:MyUserControl MyDependencyProperty="{Binding Something}" />
</Grid>
我的MainWindowVM.cs有一个属性设置,用于
某些内容
,在属性更改时发出通知

用户控件在单独的dll中创建。正如您所猜测的,
MyMVVMUserControl
将DataContext设置为视图模型

public MyMVVMUserControl()
{
    DataContext = new MyMVVMUserControlVM();
    InitializeComponent();
}
MyUserControl
在代码隐藏中未设置DataContext

所以有趣的是,它们的
MyDependencyProperty
设置完全相同

但是MVVM版本不起作用

在深入研究之后,我发现MainWindow.xaml中的
{Binding Something}
使用MyMVVMUserControl的视图模型设置作为DataContext(而不是MainWindow.cs中的DataContext集(设置为MainWindowVM))

我的问题是为什么?

为什么WPF会查看用户控件内部,并将其DataContext用于实际应用程序中的绑定


(注意:我知道我可以通过在绑定中设置源代码来解决这一问题,但我希望其他人能够使用我的用户控件。但是有了这个问题,我现在为任何我想使用我的用户控件的人提供了一个内置的“gotcha”。)

您真的不应该从
UserControl
内部设置
UserControl
DataContext
。通过这样做,您可以防止任何其他
DataContext
传递到
UserControl
,这会破坏WPF拥有独立UI和数据层的最大优势之一

如果未将
DataContext
设置为任何其他值,则WPF对象仅从父对象继承其
DataContext
。创建
MyMVVMUserControl
时,您正在将
DataContext
设置为一个新的
MyMVVMUserControlVM
,从而防止从
main窗口继承
DataContext

因此,您的
MVVMUserControl
将其
DataContext
设置为您的
MyMVVMUserControlVM
,这是正常的,因为您在UserControl的构造函数中显式地设置了它

这是故意的。WPF/MVVM中的UI对象只是数据层的可视表示,因此设置数据层,然后尝试将属性绑定到数据层之外的对象是没有多大意义的

例如,以这行代码为例:

 <UserControl DataContext="{Binding ClassA}" Content="{Binding Name}" />

在您的情况下,听起来您应该使用第一种情况,并且应该将一个
ViewModel
传递到包含所需数据的
UserControl

<extraControls:MyMVVMUserControl DataContext="{Binding MyMVVMUserControlVM}"
                                 MyDependencyProperty="{Binding Something}">


我想我理解您的问题,我将给出一个适合我的解决方案(我以前遇到过这个问题)。我们的想法是,您正在代码隐藏中为您设置
DataContext
MyMVVMUserControl
,然后它从中获取绑定

我找到的解决方案是在代码隐藏中设置datacontext,而不是在用户控件中。为
用户控件的子项设置datacontext。例如,supose这是UserControl的Xaml:

<UserControl ... x:Name="userControl">
    <Grid x:Name="rootContainer">
         ...
    </Grid>
</UserControl>

希望这能帮助您解决问题…

我强烈建议您检查正在运行的应用程序,看看每个元素的DataContext是什么。此外,应该先使用InitializeComponent()。如果InitializeComponent是第一个,则任何需要CataContext的控件都不会使用它。。。对吗?@HighCore-谢谢你给Snoop的指针。我来看看。但在本例中,我在绑定中放置了一个
PresentationTraceSources.TraceLevel=High
。这清楚地告诉我MainWindow.xaml中绑定的DataContext使用的是用户控件的DataContext.Hmmm,我一定没有理解它的意思。我有一个用户控件,它为输入特定对象数据的UI建模。但它很复杂,我需要的不是全部都在这个对象中。因此,我试图将对象作为依赖属性传入,然后使用视图模型(在用户控件中)运行UI、逻辑和命令…@Vaccano我已经更新了答案。我的用户控件几乎总是两件事之一。它们可以是ViewModel(或模型)的可视化表示,例如
CustomerUserControl
用于
CustomerServiceWModel
,在这种情况下,我会在使用它们时向它们传递所需的数据上下文。或者,它们可以是自我维持的UI对象,通过自定义DependencyProperties接收所需的任何数据,例如具有
SelectedDate
dependency属性的
DatePicker
控件。听起来您应该使用第一种情况,并且应该将ViewModel传递到包含它所需数据的UserControl中。
<DataTemplate DataType="{x:Type local:CustomerModel}">
    <local:CustomerUserControl />
</DataTemplate>
<local:DatePickerUserControl SelectedDate="{Binding SomeDate}" />

<local:CalculatorUserControl Equation="{Binding SomeString}" 
                             Value="{Binding SomeDouble}" />
<extraControls:MyMVVMUserControl DataContext="{Binding MyMVVMUserControlVM}"
                                 MyDependencyProperty="{Binding Something}">
<extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}">
    <extraControls:MyMVVMUserControl.DataContext>
        <viewModels:MyMVVMUserControlVM />
    </extraControls:MyMVVMUserControl.DataContext>
<extraControls:MyMVVMUserControl />
<UserControl ... x:Name="userControl">
    <Grid x:Name="rootContainer">
         ...
    </Grid>
</UserControl>
...
rootContainer.DataContext = new UserControlViewModel();
...