影响子继承的WPF ViewModel实例化

时间:2015-06-29 17:08:32

标签: wpf xaml mvvm binding datacontext

我有一个子用户控件(Page1),当它在XAML中声明内联时,无法继承我的WPF窗口的DataContext上设置的ViewModel(WizardPageViewModel):

<Window x:Class="WPFToolkitWizard.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:common="clr-namespace:WPFToolkitWizard"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <common:WizardPageViewModel/>
</Window.DataContext>
<Grid>
    <common:MyWizardControl>
        <common:MyWizardControl.Pages>
            <common:Page1 Title="Page 1" Description="First page" IsValid="true" />
        </common:MyWizardControl.Pages>
    </common:MyWizardControl>
</Grid>

但是,如果我将其更改为静态资源并按如下方式引用它:

<Window.Resources>
<common:WizardPageViewModel x:Key="vm" />
</Window.Resources>

<common:Page1 Title="Page 1" Description="First page" IsValid="true" DataContext="{StaticResource vm}" />

在Page1中声明的绑定取决于注入的VM工作正常。问题是我想从Window的DataContext属性引用ViewModel,因为这是我们在整个团队中声明我们的VM的方式:

<Window.DataContext>
<common:WizardPageViewModel/>
</Window.DataContext>

我已尝试按如下方式设置绑定,但没有这样的运气:

<common:Page1 Title="Page 1" Description="First page" IsValid="true" DataContext="{Binding}" />

此外,我已经阅读了有关DataContext自动继承的帖子,但它在这种情况下不起作用。

查看详细的调试输出,如下所示:

System.Windows.Data Warning: 60 : BindingExpression (hash=26218178): Default mode resolved to TwoWay
System.Windows.Data Warning: 61 : BindingExpression (hash=26218178): Default update trigger resolved to LostFocus
System.Windows.Data Warning: 62 : BindingExpression (hash=26218178): Attach to     System.Windows.Controls.TextBox.Text (hash=35377412)
System.Windows.Data Warning: 67 : BindingExpression (hash=26218178): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=26218178): Found data context element: TextBox (hash=35377412) (OK)
System.Windows.Data Warning: 71 : BindingExpression (hash=26218178): DataContext is null
System.Windows.Data Warning: 65 : BindingExpression (hash=26218178): Resolve source deferred

它声明DataContext为null,但我不知道为什么它不会自动找到我的VM实例。

MyWizardControl是一个用户控件

Page1是ContentControl

1 个答案:

答案 0 :(得分:-1)

似乎按照我的预期工作。

从代码的结构我假设common:MyWizardControlItemsControl,因为它包含Pages属性。

如果这是真的,那么ItemsControl元素(在您的情况下是您的网页)会从ItemControl的源ItemsSource属性继承ViewModel在你的情况下是ObservableCollection<WizardPageViewModel>

由于您未在ItemSource上设置ItemsControl属性,因此它是空的,WPF无法为其分配任何数据上下文。

静态版本有效,因为您明确设置它,覆盖DataContext设置的任何可能的ItemSource

话虽如此,你有三个选择:

  1. 静态实例化并自行分配,就像您在示例中所做的那样(不是很优雅)
  2. 将MVVM Framework与ViewModelLocator(即Microsofts Prism Framework)一起使用,每次实例化视图时(通过代码或从XAML)显式解析View
  3. 创建一个包含MyWizardViewModel的{​​{1}},并将其绑定到ObservableCollection<WizardPageViewModel> Pages {get;set;}的{​​{1}}。
  4. 第一个选项感觉有点脏,但对于演示或教学项目可能没问题。

    第二个适用于可重用的Views / ViewModel,如果是Prims,ViewModelLocator将为您在XAML中插入的每个ItemsSource视图创建一个ViewModel的新实例。如果使用依赖注入框架(如Unity,MEF,Autofac等),则可以在多个WizardPageViewModel控件中使用ViewModel的单个实例。

    第三个选项是首选,因为ViewModel旨在与视图一起使用,Page1Page1,而不是View(实际上Page1是它拥有子视图的视图,每个视图都意味着拥有它自己的ViewModel来表示View需要的数据。

    第三个选项是最容易实现的,无需使用MVVM框架或依赖注入

    编辑:示例

    MyWizardControl

    XAML:

    MyWizardControl

    然后您只需为每个ViewModel创建DataTemplates,然后ContenControl将根据DataContext的类型显示正确的模板。见here