我有一个子用户控件 (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 中声明的依赖于注入(inject)的 VM 的绑定(bind)可以正常工作。问题是我想从 Window 的 DataContext 属性中引用 ViewModel,因为这是我们在整个团队中声明我们的 VM 的方式:
<Window.DataContext>
<common:WizardPageViewModel/>
</Window.DataContext>
我尝试按如下方式设置绑定(bind),但没有这样的运气:
<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 为空,但我只是不知道为什么它不能自动找到我的 VM 实例。
MyWizardControl 是一个用户控件
Page1 是一个 ContentControl
最佳答案
似乎对我来说按预期工作。
根据您的代码结构,我假设 common:MyWizardControl
是 ItemsControl
,因为它包含一个 Pages
属性(property)。
如果这是真的,那么 ItemsControl
元素(在您的情况下是您的页面)从 ItemControl
继承 ViewModel的来源ItemsSource
属性,这将是 ObservableCollection<WizardPageViewModel>
在你的情况下。
由于您没有设置 ItemSource
ItemsControl
上的属性(property),它是空的,WPF 不能为其分配任何数据上下文。
静态的有效,因为您明确设置它,覆盖任何可能的 DataContext
由 ItemSource
设置.
话虽如此,您有三个选择:
View
每次实例化 View 时(通过代码或从 XAML)MyWizardViewModel
其中包含 ObservableCollection<WizardPageViewModel> Pages {get;set;}
并将其绑定(bind)到 ItemsSource
的 WizardPageViewModel
. 第一个选项感觉有点脏,但对于演示或教学项目可能没问题。
第二个适用于可重用的 View / View 模型,如果是 Prims,ViewModelLocator 将为每个
Page1
创建一个 View 模型的新实例。查看您在 XAML 中插入的内容。您可以在多个 Page1
中使用 ViewModel 的单个实例控制是否使用依赖注入(inject)框架(如 Unity、MEF、Autofac 等)第三个选项是首选,因为 ViewModel 旨在与 View 和您的
View
一起使用。是 Page1
,而不是 MyWizardControl
(实际上 MyWizardControl
是一个带有 subview 的 View ,每个 View 都有自己的 View 模型,代 TableView 所需的数据)。第三种选择是最容易实现的,无需使用 MVVM 框架或依赖注入(inject)
编辑:一个例子
// Prism ViewModel base class, adjust for your framework or whatever you use as base
public class MyWizardViewModel : BindableBase
{
public ObservableCollection<WizardPageViewModel> Pages { get; set; }
public MyWizardViewModel()
{
Pages = new ObservableCollection<WizardPageViewModel>()
{
new WizardPage1ViewModel(), // public class WizardPage1ViewModel : WizardPageViewModel
new WizardPage2ViewModel() // public class WizardPage2ViewModel : WizardPageViewModel
}
}
}
XAML:
<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 ItemsSource="{Binding Pages}" />
</Grid>
然后您只需为每个 ViewModel 制作 DataTemplates,然后 ContenControl 将根据 DataContext 的类型显示正确的模板。见 here
关于WPF ViewModel 实例化影响子继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31121566/