我一直在尝试学习如何使用 WPF 正确使用 MVVM。
在实践中,MVVM 可以用一句话来概括:视图模型负责提供其视图所需的所有数据和功能。
当操作范围超出视图模型时,您如何使用命令?
在 MVVM 中,每个视图都有一个视图模型,因此没有比视图模型更远的。在 WPF 中处理 ICommands 使用的一种好方法是使用基于 delegate 的 Commands 之一,例如流行的 RelayCommand。您可以在 MSDN 上的WPF Apps With The Model-View-ViewModel Design Pattern 页面中找到详细信息。
在 UI 中,它们的使用与任何其他 ICommand 一样,但在视图模型中,您可以只使用方法甚至内联 delegates 来处理 ICommand.Execute 和 ICommand.CanExecute 方法。我使用我自己的RelayCommand 版本,对于您的场景,我会这样做:
public ICommand CloseCommand
{
get
{
return new ActionCommand(action => Close(null), canExecute => CanClose(null));
}
}
private void Close(object commandParameter)
{
if (SomeDataItem.HasChanges)
{
if (WindowManager.AskUserIfTheyWantToSave(SomeDataItem))
DataProvider.Save(SomeDataItem);
}
HardDriveManager.SaveSettings();
WindowManager.CloseMainWindow();
}
现在很明显,你没有我的 ...Manager 课程,但你如何保存这个和那个并不重要......这只是向你展示了什么是可能的。
如果关闭应用程序还需要其他操作,例如关闭数据库连接,该怎么办?
现代数据库技术实际上并不需要您在任何时候手动关闭数据库连接。
在这一点上,我想明确一点,当使用 MVVM 时,在UserControls 甚至MainWindow 后面的代码中处理事件是完全可以接受的.所以像这样在MainWindow.xaml.cs中保存设置绝对没有问题:
Loaded += MainWindow_Loaded;
Closing += MainWindow_Closing;
...
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Settings.Default.Reload();
WindowStartupLocation = WindowStartupLocation.Manual;
Left = Settings.Default.ApplicationLocation.X;
Top = Settings.Default.ApplicationLocation.Y;
Width = Settings.Default.ApplicationSize.Width;
Height = Settings.Default.ApplicationSize.Height;
WindowState = Settings.Default.IsApplicationMaximised ? WindowState.Maximized : WindowState.Normal;
}
private void MainWindow_Closing(object sender, EventArgs e)
{
Settings.Default.ApplicationLocation = new Point(Left, Top);
Settings.Default.ApplicationSize = new Size(Width, Height);
Settings.Default.IsApplicationMaximised = WindowState == WindowState.Maximized;
Settings.Default.Save();
}
我是否在视图模型中声明事件并让命令触发事件?
事件是 UI 对象,不应该在视图模型中看到......我们不希望在视图模型项目引用中出现任何与 UI 相关的 dll。当你真的需要处理一个事件时,你可以在后面的代码中处理它,记住你可以像这样从后面的视图代码中访问数据绑定视图模型:
SomeViewModel viewModel = (SomeViewModel)DataContext;
或者更好的方法是在附加属性中处理事件,您可以在 XAML 中简单地附加该事件。我建议您不要扩展这个相当长的答案来解释如何做到这一点,而是在线搜索,因为有很多例子。哦,实际上,我只记得我在 Stack Overflow 上的 What's the best way to pass event to ViewModel? 帖子中向某人解释了如何执行此操作。
所以这比我预期的要长,但希望它回答了你的(一些)问题。