WPF ViewModel实例化影响子继承
我有一个子用户控件(Page1),当其在XAML中声明为内联时,该控件无法继承在WPF窗口的DataContext上设置的ViewModel(WizardPageViewModel):WPF ViewModel实例化影响子继承,wpf,xaml,mvvm,binding,datacontext,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.
<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>
它声明DataContext为null,但我不知道为什么它不能自动找到我的VM实例
MyWizardControl是一个用户控件
Page1是一个ContentControl对我来说似乎像预期的那样工作 根据代码的结构,我假设
common:MyWizardControl
是一个ItemsControl
,因为它包含一个Pages
属性
如果这是真的,那么ItemsControl
元素(在您的例子中是您的页面)将从ItemsControl
的源ItemsSource
属性继承ViewModel,在您的例子中,该属性将是一个observedcollection
由于未在ItemsControl
上设置ItemSource
属性,因此该属性为空,WPF无法为其分配任何数据上下文
静态设置有效,因为您显式地设置了它,覆盖了由ItemSource
设置的任何可能的DataContext
话虽如此,您有三种选择:
MyWizardViewModel
,其中包含一个ObservableCollection Pages{get;set;}
,并将其绑定到WizardPageViewModel
的ItemsSource
Page1
视图创建一个新的ViewModel实例。如果使用依赖项注入框架(如Unity、MEF、Autofac等),则可以在多个Page1
控件中使用ViewModel的单个实例
第三个选项是首选选项,因为ViewModel将与视图一起使用,视图
是页面1
,而不是MyWizardControl
(实际上MyWizardControl
是一个具有子视图的视图,每个视图都有自己的视图模型,表示视图所需的数据)
第三个选项是最容易实现的,无需使用MVVM框架或依赖项注入
编辑:一个示例
// 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
}
}
}
//Prism ViewModel基类,根据您的框架或任何用作基类的内容进行调整
公共类MyWizardViewModel:BindableBase
{
公共可观察集合页面{get;set;}
公共MyWizardViewModel()
{
Pages=新的ObservableCollection()
{
新建WizardPage1ViewModel(),//公共类WizardPage1ViewModel:WizardPageViewModel
新建WizardPage2ViewModel()//公共类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,然后ContentControl将根据DataContext的类型显示正确的模板。参见他说
MyWizardControl
是一个UserControl
。Page1是一个ContentControl。他基本上是在UserControl上的一个集合中添加一个ContentControl。此外,如果他选择只使用静态资源路径,他需要确保并设置。否则,视图模型实例将来可能会与其他元素共享,因为WPF将其视为一个单例实例。它的复数形式表明,它将能够包含多个视图,并且只有ItemsControl
用于此目的。MyWizardControl
或Pages
是一个ItemsControl
或从它派生的东西(TabControl
,等等),否则不能在其中承载多个视图。不管是什么情况,事实仍然是,它与ItemsControl
以及它管理ItemsSource
元素的数据上下文的方式有关。我知道您正在尝试为它找到解决方法,但要小心将VM用作静态资源。所有资源(静态和动态)都是共享实例,因此绑定到该资源的任何其他资源都将被赋予与本例中的窗口相同的实例。如果无法使其工作,请确保并设置为false。
<common:Page1 Title="Page 1" Description="First page" IsValid="true" DataContext="{Binding}" />
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
// 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
}
}
}
<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>