Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
WPF ViewModel实例化影响子继承_Wpf_Xaml_Mvvm_Binding_Datacontext - Fatal编程技术网

WPF ViewModel实例化影响子继承

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.

我有一个子用户控件(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>
它声明DataContext为null,但我不知道为什么它不能自动找到我的VM实例

MyWizardControl是一个用户控件


Page1是一个ContentControl

对我来说似乎像预期的那样工作

根据代码的结构,我假设
common:MyWizardControl
是一个
ItemsControl
,因为它包含一个
Pages
属性

如果这是真的,那么
ItemsControl
元素(在您的例子中是您的页面)将从
ItemsControl
的源
ItemsSource
属性继承ViewModel,在您的例子中,该属性将是一个
observedcollection

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

静态设置有效,因为您显式地设置了它,覆盖了由
ItemSource
设置的任何可能的
DataContext

话虽如此,您有三种选择:

  • 静态实例化它并自己分配,就像您在示例中所做的那样(不是很优雅)
  • 使用带有ViewModelLocator的MVVM框架(即Microsofts Prism框架),该框架将在每次实例化视图时(通过代码或从XAML)显式解析视图
  • 创建一个
    MyWizardViewModel
    ,其中包含一个
    ObservableCollection Pages{get;set;}
    ,并将其绑定到
    WizardPageViewModel
    ItemsSource
  • 第一个选项感觉有点脏,但对于演示或教学项目来说可能还不错

    第二种方法适用于可重用视图/视图模型,对于Prims,ViewModelLocator将为插入XAML中的每个
    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>