WPF MVVM和将viewmodels传递给视图
我是WPF的新手,现在我正在尝试适应MVVM模式。现在,我有一个简单的应用程序,其中我有一组视图模型,显示在网格中。双击网格中的行时,我希望显示ViewModel的详细视图 我现在遇到的问题是,我已经有了一个完全实例化的ViewModel,但我似乎无法将其传递到视图中。当我尝试加载该视图时,它显示为空。我已经发现,这是因为当加载视图时,它会创建自己的备份视图模型实例。因此,显然我需要绕过这种行为,并在创建实例ViewModel时以某种方式将其传递到视图中。我可以在视图中使用一个构造函数,它接受一个ViewModel并在其中设置数据源。但是,采用这种方法意味着我需要在ViewModel中构造视图,从而使ViewModel知道该视图。这是我想要避免的,因为我试图维护MVVM模式 那么在这种情况下我该怎么办?我应该打破MVVM模式,还是有一些好的、干净的解决方案适合MVVM模式?有很多方法可以将视图模型传递给视图(如您所称),或者将视图模型设置为窗口或用户控件(如其他人所称)的DataContext。最简单的就是: 在视图构造函数中:WPF MVVM和将viewmodels传递给视图,wpf,mvvm,Wpf,Mvvm,我是WPF的新手,现在我正在尝试适应MVVM模式。现在,我有一个简单的应用程序,其中我有一组视图模型,显示在网格中。双击网格中的行时,我希望显示ViewModel的详细视图 我现在遇到的问题是,我已经有了一个完全实例化的ViewModel,但我似乎无法将其传递到视图中。当我尝试加载该视图时,它显示为空。我已经发现,这是因为当加载视图时,它会创建自己的备份视图模型实例。因此,显然我需要绕过这种行为,并在创建实例ViewModel时以某种方式将其传递到视图中。我可以在视图中使用一个构造函数,它接受一
public partial class SomeView
{
InitializeComponent();
DataContext = new SomeViewModel();
}
更具MVVM的方法可能是在App.xaml中为每个视图模型定义DataTemplates,该视图模型定义了每个视图将使用的视图:
<DataTemplate DataType="{x:Type YourViewModelsPrefix:YourViewModel">
<YourViewsPrefix:YourView />
</DataTemplate>
...
<DataTemplate DataType="{x:Type YourViewModelsPrefix:AnotherViewModel">
<YourViewsPrefix:AnotherView />
</DataTemplate>
甚至在这样的收藏中:
<ContentControl Content="{Binding YourViewModelProperty}" />
<ListBox ItemsSource="{Binding YourViewModelCollectionProperty}" />
public class ViewFactory
{
public UIElement Create(object context)
{
// Create the view model
// You can pass in various information by parameters
// as I do with context (Constructor Injection)
var viewModel = new ViewModel(context);
// Create the view and set the view model as data context
var view = new View { DataContext = viewModel };
return view;
}
}
有许多方法可以将视图模型传递给视图(您称之为视图),或者将视图模型设置为窗口或用户控件的DataContext(其他人可能称之为)。最简单的就是:
在视图构造函数中:
public partial class SomeView
{
InitializeComponent();
DataContext = new SomeViewModel();
}
更具MVVM的方法可能是在App.xaml中为每个视图模型定义DataTemplates,该视图模型定义了每个视图将使用的视图:
<DataTemplate DataType="{x:Type YourViewModelsPrefix:YourViewModel">
<YourViewsPrefix:YourView />
</DataTemplate>
...
<DataTemplate DataType="{x:Type YourViewModelsPrefix:AnotherViewModel">
<YourViewsPrefix:AnotherView />
</DataTemplate>
甚至在这样的收藏中:
<ContentControl Content="{Binding YourViewModelProperty}" />
<ListBox ItemsSource="{Binding YourViewModelCollectionProperty}" />
public class ViewFactory
{
public UIElement Create(object context)
{
// Create the view model
// You can pass in various information by parameters
// as I do with context (Constructor Injection)
var viewModel = new ViewModel(context);
// Create the view and set the view model as data context
var view = new View { DataContext = viewModel };
return view;
}
}
我同意@Sheridan的回答,只想添加另一种使用视图模型实例化视图的方法:您可以使用工厂模式,可能如下所示:
<ContentControl Content="{Binding YourViewModelProperty}" />
<ListBox ItemsSource="{Binding YourViewModelCollectionProperty}" />
public class ViewFactory
{
public UIElement Create(object context)
{
// Create the view model
// You can pass in various information by parameters
// as I do with context (Constructor Injection)
var viewModel = new ViewModel(context);
// Create the view and set the view model as data context
var view = new View { DataContext = viewModel };
return view;
}
}
您可以从视图模型的方法中调用此工厂,然后将其分配给例如绑定到UI的数据属性。这允许更大的灵活性-但是@Sheridan的解决方案也很好。我同意@Sheridan的回答,只想添加另一种方法来使用视图模型实例化视图:您可以使用Factory模式,可能如下所示:
<ContentControl Content="{Binding YourViewModelProperty}" />
<ListBox ItemsSource="{Binding YourViewModelCollectionProperty}" />
public class ViewFactory
{
public UIElement Create(object context)
{
// Create the view model
// You can pass in various information by parameters
// as I do with context (Constructor Injection)
var viewModel = new ViewModel(context);
// Create the view and set the view model as data context
var view = new View { DataContext = viewModel };
return view;
}
}
您可以从视图模型的方法中调用此工厂,然后将其分配给例如绑定到UI的数据属性。这允许更大的灵活性,但是@Sheridan的解决方案也很好
我应该打破MVVM模式吗
请考虑更多地了解这个模式,知道打破它是什么。此模式的主要目的是明确责任,从而获得可测试和可维护的代码。这方面有很多资源,如本问题所示:
无论如何,为了更具体地回答您的问题,您需要的是如何设置DataContext
创建实例化的ViewModel时,以某种方式将其传递到视图中
是的,您知道,如果在视图的构造函数中为dataContext分配viewModel,它可能会工作,但只有当viewModel有责任创建视图时,它才是可接受的,而在很少的情况下,视图才是可接受的。您甚至可以编写类似的内容,从视图外部直接设置DataContext:
var l_window = new MyView { DataContext = new MyViewModel() };
l_window.Show();
[Import]
private MyViewModel ViewModel
{
set { this.DataContext = value; }
get { return this.DataContext as MyViewModel; }
}
当然,该代码的主要缺点是不可测试。如果你想测试它,你应该使用一个可模仿的服务来管理视图的创建
一个更常见的解决方案是向dataContext注入类似prism的IOC容器。您可以在软件启动时创建所有必需的ViewModel,并将它们存储在此IOC容器中。然后,在创建视图时,要求此容器获取viewModel的实例
例如:在PRISM中导出viewModel:
[Export]
public class MyViewModel {...}
然后在视图中导入它:
var l_window = new MyView { DataContext = new MyViewModel() };
l_window.Show();
[Import]
private MyViewModel ViewModel
{
set { this.DataContext = value; }
get { return this.DataContext as MyViewModel; }
}
希望能有帮助
我应该打破MVVM模式吗
请考虑更多地了解这个模式,知道打破它是什么。此模式的主要目的是明确责任,从而获得可测试和可维护的代码。这方面有很多资源,如本问题所示:
无论如何,为了更具体地回答您的问题,您需要的是如何设置DataContext
创建实例化的ViewModel时,以某种方式将其传递到视图中
是的,您知道,如果在视图的构造函数中为dataContext分配一个viewModel,它可以工作,但只有当viewModel有责任创建一个
在非常少的情况下是可以接受的。您甚至可以编写类似的内容,从视图外部直接设置DataContext:
var l_window = new MyView { DataContext = new MyViewModel() };
l_window.Show();
[Import]
private MyViewModel ViewModel
{
set { this.DataContext = value; }
get { return this.DataContext as MyViewModel; }
}
当然,该代码的主要缺点是不可测试。如果你想测试它,你应该使用一个可模仿的服务来管理视图的创建
一个更常见的解决方案是向dataContext注入类似prism的IOC容器。您可以在软件启动时创建所有必需的ViewModel,并将它们存储在此IOC容器中。然后,在创建视图时,要求此容器获取viewModel的实例
例如:在PRISM中导出viewModel:
[Export]
public class MyViewModel {...}
然后在视图中导入它:
var l_window = new MyView { DataContext = new MyViewModel() };
l_window.Show();
[Import]
private MyViewModel ViewModel
{
set { this.DataContext = value; }
get { return this.DataContext as MyViewModel; }
}
希望能有帮助