C# 为什么绑定到用户控件上的DependencyProperty会使用用户控件';什么是数据上下文?
假设我有一个WPF应用程序(exe),它在MainWindow.xaml中包含以下内容: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
<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();
...