1

假设我在 MainWindow.xaml 中有一个 WPF 应用程序 (exe):

<Grid>
    <extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}"/>
    <extraControls:MyUserControl MyDependencyProperty="{Binding Something}" />
</Grid>

我的 MainWindow.xaml.cs 看起来像这样:

public MainWindow()
{
    DataContext = new MainWindowVM();
    InitializeComponent();
}

我的 MainWindowVM.cs 有一个属性设置,用于Something通知属性更改。

用户控件是在单独的 dll 中制作的。正如您可能猜到的那样,MyMVVMUserControl将 DataContext 设置为视图模型。

public MyMVVMUserControl()
{
    DataContext = new MyMVVMUserControlVM();
    InitializeComponent();
}

MyUserControl在后面的代码中没有设置 DataContext。

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

但是 MVVM 版本不起作用。

在深入研究之后,我发现MainWindow.xaml{Binding Something}中的 View Model 设置为 MyMVVMUserControl 用作 DataContext(而不是 MainWindow.cs 中设置的 DataContext(设置为 MainWindowVM))。

我的问题是为什么?

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

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

4

2 回答 2

2

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

我为此找到的解决方案是在后面的代码中设置数据上下文,而不是在用户控件中。设置 的UserControl子项的数据上下文。例如,假设这是您的 UserControl 的 Xaml:

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

然后在后面的代码中设置rootContainer's 的数据上下文,这样所有的视觉孩子都可以访问控件数据上下文,并且用户控件的数据上下文是空的。

...
rootContainer.DataContext = new UserControlViewModel();
...

希望这可以帮助您解决您的问题...

于 2013-02-07T20:41:53.067 回答
1

你真的不应该DataContext从. 通过这样做,您可以防止任何其他内容传递给 . ,这破坏了 WPF 拥有独立 UI 和数据层的最大优势之一。UserControlUserControlDataContextUserControl

如果 wpf 对象未设置为其他任何值,则 WPF 对象仅从DataContext父对象继承它们。DataContext创建时,您MyMVVMUserControl将 设置DataContext为 new MyMVVMUserControlVM,以防止DataContext从 继承MainWindow

因此,您MVVMUserControl将其DataContext设置为 your是正常的MyMVVMUserControlVM,因为您在 UserControl 的构造函数中明确设置了它。

这是设计使然。WPF/MVVM 中的 UI 对象仅是数据层的可视化表示,因此设置数据层然后尝试将您的属性绑定到不在数据层上的东西没有多大意义。

例如,以这行代码为例:

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

这会将Content属性绑定到UserControl.DataContext.Name,即ClassA.Name。如果这会导致绑定到UserControl.Parent.DataContext.Name,那将没有多大意义,因为绑定应该引用当前对象的DataContext,而不是父对象的DataContext

所以我唯一一次从内部设置DataContexta是它自己的独立对象,它永远不会与来自应用程序其余部分的数据进行交互。迄今为止从未有过:)UserControlUserControlUserControl

通常我UserControls的几乎总是两件事之一:

  • a ViewModel(or Model) 的可视化表示,例如 a CustomerUserControlfor a CustomerViewModel,在这种情况下,我将它们传递给DataContext它们使用时所需的

    例如,

    <local:CustomerUserControl DataContext="{Binding SelectedCustomer}" />
    

    或者

    <DataTemplate DataType="{x:Type local:CustomerModel}">
        <local:CustomerUserControl />
    </DataTemplate>
    
  • 或者一个自我维持的 UI 对象,它通过 custom 接收它需要的任何外部数据DependencyProperties,并在控件的代码隐藏中执行任何其他逻辑,例如具有依赖属性的DatePicker控件SelectedDate,或者CalculatorUserControl具有依赖属性的控件EquationValue

    <local:DatePickerUserControl SelectedDate="{Binding SomeDate}" />
    
    <local:CalculatorUserControl Equation="{Binding SomeString}" 
                                 Value="{Binding SomeDouble}" />
    

在您的情况下,听起来您应该使用第一种情况,并且应该将 a 传递给ViewModel包含UserControl它需要的数据的您。

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

或者

<extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}">
    <extraControls:MyMVVMUserControl.DataContext>
        <viewModels:MyMVVMUserControlVM />
    </extraControls:MyMVVMUserControl.DataContext>
<extraControls:MyMVVMUserControl />
于 2013-02-07T20:21:46.790 回答