我希望这个问题不是一般的。
我习惯在MVVM-Pattern中实现我的WPF-Applications。所以我总是为View
创建一个文件夹,一个用于ViewModel
,一个用于Model
(以及一些其他文件夹用于行为,转换器......)
首先我将MainWindowView.xaml
放入View
- 文件夹。然后我将MainWindowViewModel.cs
添加到ViewModel
- 文件夹中。在此之后,我在MainWindowModel.cs
- 文件夹中添加了Model
- 文件。
MainWindowModel.cs
- 文件是我有问题的地方。
我习惯将这个类用于我的业务逻辑,比如从数据库加载数据或解析xml文件并将结果放入集合中。
例如,如果我想在Button-Click上从XML文件加载数据,我会用以下内容加载:
MainWindowView
<Window x:Class="MVVMExample.View.MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:MVVMExample.ViewModel"
Title="MainWindowView" Height="300" Width="300">
<Window.DataContext>
<viewModel:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Button Command="{Binding LoadDataCommand}" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10" Content="Load data" Width="120"/>
</Grid>
</Window>
MainWindowViewModel
internal class MainWindowViewModel : ViewModelBase
{
private readonly MainWindowModel mainWindowModel;
public MainWindowViewModel()
{
mainWindowModel = new MainWindowModel();
mainWindowModel.XmlEntriesLoaded += XmlEntriesLoaded;
LoadDataCommand = new RelayCommand(LoadData);
}
private void XmlEntriesLoaded(object sender, GenericEventArgs<List<XmlEntry>> e)
{
List<XmlEntry> entries = e.Value;
// Display entries in ObservableCollection
}
private void LoadData(object parameter)
{
mainWindowModel.LoadData();
}
private ICommand loadDataCommand;
public ICommand LoadDataCommand
{
get { return loadDataCommand; }
set
{
loadDataCommand = value;
OnPropertyChanged();
}
}
}
MainWindowModel
internal class MainWindowModel
{
public EventHandler<GenericEventArgs<List<XmlEntry>>> XmlEntriesLoaded;
public void LoadData()
{
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += (s, e) =>
{
// Do load the data here and assign the result to e.Result
};
backgroundWorker.RunWorkerCompleted += (s, e) =>
{
EventHandler<GenericEventArgs<List<XmlEntry>>> temp = XmlEntriesLoaded;
if (temp != null)
{
temp(this, new GenericEventArgs<List<XmlEntry>>((List<XmlEntry>) e.Result));
}
};
backgroundWorker.RunWorkerAsync();
}
}
班级XmlEntry
也位于Model
- 文件夹中。
现在有人告诉我,模型层只包含业务对象,没有我在MainWindowModel
中做过的逻辑。加载数据的交互应该位于ViewModel
。那是不是很严格?所以我做错了?
答案 0 :(得分:3)
我之前就此有过一些争论。您的模型不仅仅是一个愚蠢的数据对象,它应该包含与 ViewModel 类似的行为。
考虑一下这个例子:
class Camera
{
BitmapImage CurrentFrame { get; set; }
BitmapImage CapturedFrame { get; set; }
VideoCaptureDevice CaptureDevice { get; set; }
void TakePhoto();
void ClearFrame();
void Reset();
}
以上只是一些没有实现的示例代码,但您明白了。
这里的要点是TakePhoto
和Reset
等方法如果包含在模型中而不是 ViewModel 。这是一个好主意的原因之一是因为它确保您的模型可以被多个ViewModel使用,而不必在多个ViewModel中实现逻辑,因为逻辑包含在模型中。
也就是说,在某些情况下,模型没有任何行为,只能作为数据对象。
回答你的问题:
模型只知道自己,因此在您的方案中,加载模型的责任是 ViewModel 。将加载方法放在ViewModel中是正确的。
更进一步,如果您的模型逻辑加载包含在 Service 类中,那么您的ViewModel可以引用该服务以加载相应的楷模。这将允许多个ViewModel引用服务并减少代码重复。
答案 1 :(得分:1)
我不会说你这样做错误本身。通常我的Model类是非常基本的东西,它只定义了我的程序所需的对象。 ViewModel包含一组由View绑定的方法和属性,它们使用Model类。 “普通”MVVM模式将具有1个View to 1 ViewModel,然后是许多定义业务对象的Model类,然后是支持ViewModel中定义的操作所需的任何补充类。
我通常将你的'LoadData'方法放入它自己的类中,称为'DataService',它将负责程序所需的任何外部数据操作。它与您的Model类不同,它只是定义对象,但不一定属于您的ViewModel严格定义的范围。
答案 2 :(得分:1)
Model
- ViewModel
- View
之间的关系不是1:1:1。
它更像是M:N:O。
因此,多个Views
可以使用一个ViewModel
,而一个ViewModel
可以使用多个Models
。
通常Model
包含类定义数据结构及其关系,如实体框架类。我通常为Model
类提供单独的VS项目。所以例如如果您的应用使用3个数据库,则VS解决方案中可以有3个模型。模型类名称应遵循应用程序的UML类模型或数据库模型,并使用适当的名称。 MainWindowModel
不是模型类的好名字 - 它表明它属于MainWindow
,这是错误的 - 它应该包含通常可用的类。
因此,如果LoadData()
中MainWindowModel
的代码通常有用且会被多个ViewModels
或其他组件使用,那么您应该将其放入Model
在一个名为例如的类中CustomerXMLData
。 但也可以使ViewModel
根本不使用Model
类。即您不必为每个XXXWindowModel
创建ViewModel
类 - 这不是MVVM的重点。重点是模块化代码的可重用性和良好的设计,没有重复的代码。