2017-03-07 63 views
0

我在实例化viewModels时遇到了问题。MVVM View vs ViewModel绑定问题

我在大多数情况下使用ViewModelLocator,因为我必须注入依赖关系。不过,有时候我需要将参数传递给ViewModel。据我所知,我需要使用ViweModel-First方法。这意味着我需要为运行时绑定到视图的ViewModel创建一个DataTemplate。确保包含一个构造函数与我想传入的参数。

我遇到的问题是,当我创建ViewModel并传入我的参数时,会调用正确的构造函数。但是因为ViewModel绑定到视图,所以视图调用视图模型的默认无参数构造函数。

这里是什么XAML看起来像该用户控件我视图模型结合:

<UserControl x:Class="MyView"> 
    <UserControl.DataContext> 
     <viewModels:MyViewModel></viewModels:MyViewModel> 
    </UserControl.DataContext> 
</UserControl> 

数据模板看起来是这样的:

<DataTemplate DataType="{x:Type viewModels:MyViewModel}"> 
    <views:MyView></views:MyView> 
</DataTemplate> 

下面是一个简单的ViewModel:

public class MyViewModel : ViewModelBase 
{ 
    private MyModel _myModel; 

    public MyViewModel() 
    { 
    } 

    public MyViewModel(MyModel myModel) 
    { 
    _myModel = myModel; 
    } 
} 

一旦我创建我的viewModel通过代码使用正确的构造函数来传递参数ments,viewModel是由视图使用viewModel的默认无参构造函数重新创建的。

任何人都可以解释为什么会发生这种情况,并阐明如何设置viewmodel优先方法,使其正常工作?我很茫然,我一整天都在努力。

感谢, 添

回答

1

如果您从UserControl删除下面的代码片段,并按照我剩下的指示,我相信你会有你想要的东西:

删除此

<UserControl.DataContext> 
     <viewModels:MyViewModel></viewModels:MyViewModel> 
</UserControl.DataContext> 

现在,假设你有一个UserControlWindow绑定到ViewModel,你想要代表你ur UserControlWindow。你这样做的方式是结合在ResourceDictionary像这样指定的DataTemplate使用ContentControlUserControlWindow内:

.XAML:

<Window x:Class="WPF_Sandbox.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:vm="clr-namespace:WpfApplication1.ViewModels" 
    Title="MainWindow" 
    x:Name="ThisControl"> 
    <Window.DataContext> 
     <vm:MainWindowViewModel/> 
    </Window.DataContext> 
    <DockPanel LastChildFill="True"> 
     <ContentControl DockPanel.Dock="Left" Content="{Binding NavigationRegion}"/> 
     <ContentControl DockPanel.Dock="Left" Content="{Binding ContentRegion}"/> 
    </DockPanel>  
</Window> 

ContentControl将隐式的查找与ViewModel关联的与Content属性绑定的DataTemplate(在ResourceDictionary对象的层次结构中)。因此,可以说,我们在MainWindowViewModelContentRegion属性设置为您MyViewModel像这样的实例:

MainWindowViewModel。CS

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace WpfApplication1.ViewModels 
{ 
    public class MainWindowViewModel : ViewModel 
    { 
     private object _navigationRegion; 
     private object _contentRegion; 

     public object NavigationRegion 
     { 
      get 
      { 
       return _navigationRegion; 
      } 
      set 
      { 
       _navigationRegion = value; 
       OnPropertyChanged(nameof(NavigationRegion)); 
      } 
     } 

     public object ContentRegion 
     { 
      get 
      { 
       return _contentRegion; 
      } 
      set 
      { 
       _contentRegion = value; 
       OnPropertyChanged(nameof(ContentRegion)); 
      } 
     } 

     public MainWindowViewModel() 
     { 
      ContentRegion = new MyViewModel(new MyModel()); 
     } 
    } 
} 

而且你有像这样一个ResourceDictionary规定:

MyResourceDictionary.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:local="clr-namespace:WpfApplication1" 
        xmlns:vm="clr-namespace:WpfApplication1.ViewModels" 
        xmlns:views="clr-namespace:WpfApplication1.Views"> 
    <DataTemplate DataType="{x:Type vm:MyViewModel}"> 
     <views:MyView/> 
    </DataTemplate> 

</ResourceDictionary> 

而且你已经合并了你的ResourceDictionaryApplication.Resources在App.xaml文件像所以:

<Application x:Class="WpfApplication1.App" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:local="clr-namespace:WpfApplication1" 
      StartupUri="MainWindow.xaml"> 
    <Application.Resources> 
     <ResourceDictionary> 
      <ResourceDictionary.MergedDictionaries> 
       <ResourceDictionary Source="MyResourceDictionary.xaml"/> 
      </ResourceDictionary.MergedDictionaries> 
     </ResourceDictionary> 
    </Application.Resources> 
</Application> 

该框架将隐式地查找数据类型MyViewModelDataTemplate。该框架将在我们指定的ResourceDictionary中找到DataTemplate,MyViewModel,并看到它应该由MyView用户控件表示。在这一点上,框架将呈现MyView用户控件。

和对子孙后代着想:

ViewModel.cs

using System.ComponentModel; 

namespace WpfApplication1.ViewModels 
{ 
    public abstract class ViewModel : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     protected string _title; 

     protected string Title 
     { 
      get 
      { 
       return _title; 
      } 
      set 
      { 
       _title = value; 
       OnPropertyChanged(nameof(Title)); 
      } 
     } 

     protected void OnPropertyChanged(string propName) 
     { 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); 
     } 
    } 
} 
+1

请出示一些代码,所以我可以提供帮助。目前还不清楚你的评论是什么问题。 – user1286901

+0

我对此感到抱歉。我不能从办公室发帖。它被锁定。基本上你回答了我的问题。有2个问题。首先,由于定位器用于实例化视图模型,因此使用定位器在视图中绑定上下文也会再次称为viemodel。第二个问题是在内容控制中返回并显示的用户控件中定义数据上下文。所以它被控件和代码调用。再次感谢。 – user953710