我在实例化viewModels时遇到了问题。
我大部分时间都在使用ViewModelLocator,因为在大多数情况下我必须注入依赖项。但是有些情况下我需要将参数传递给ViewModel。据我所知,我需要使用ViweModel-First方法。这意味着我需要为ViewModel创建一个DataTemplate,它在运行时绑定到View。确保包含一个带有我想传入的参数的构造函数。
我遇到的问题是,当我创建ViewModel并传入我的参数时,会调用正确的构造函数。但是因为ViewModel绑定到视图,所以视图调用viewmodel的默认无参数构造函数。
以下是我将ViewModel绑定到的UserControl的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来传递参数,视图将使用viewModel的默认无参数构造函数再次创建viewModel。
任何人都可以解释为什么会发生这种情况并阐明如何设置viewmodel-first方法以使其正常工作?我很茫然,我一整天都在努力。
谢谢, 添
答案 0 :(得分:1)
如果您从UserControl
删除以下代码段并按照我的其余说明操作,我相信您会得到您想要的内容:
删除此
<UserControl.DataContext>
<viewModels:MyViewModel></viewModels:MyViewModel>
</UserControl.DataContext>
现在,假设您希望在UserControl
或Window
中代表ViewModel
或UserControl
绑定到Window
。这样做的方法是使用ContentControl
或UserControl
内的Window
以及DataTemplate
中指定的ResourceDictionary
,如下所示:
<强> .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
将隐式查找与绑定到其DataTemplate
属性的ResourceDictionary
关联的ViewModel
(在Content
个对象的层次结构中)。因此,我们假设我们将ContentRegion
中的MainWindowViewModel
属性设置为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>
您已将ResourceDictionary
与App.xaml文件中的Application.Resources
合并,如下所示:
<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>
框架将隐式地为数据类型DataTemplate
寻找MyViewModel
。框架将在我们指定的DataTemplate
中找到MyViewModel
的{{1}},并看到它应由ResourceDictionary
用户控件表示。此时,框架将呈现MyView
用户控件。
为了后人的缘故:
<强> ViewModel.cs 强>
MyView