在 WPF MVVM 中验证和保存数据如何正确工作?

ygo*_*goe 5 c# database wpf mvvm

我是 MVVM(和一些 WPF)的新手,最近几天我阅读了许多代码项目文章、博客文章和 Stackoverflow 问题。我的印象是数据绑定非常适合显示从数据源(数据库)加载后的数据,并使模型与视图保持同步,同时更新视图中模型数据的所有其他外观。

但我仍然不知道如何保存,在验证之前,应该如何正常工作。我有很强的 Windows 窗体和 ADO.NET 背景。我非常熟悉数据库访问层和视图更新的编码。那时,您只有在视图中进行编辑的临时临时数据,以及模型类和数据库中数据的最后保存版本。模型类通常与数据库同步。该视图包含尚未保存的数据。

您还有一个 Save 按钮,可以从控件中读取所有数据,在代码中对其进行验证,然后接受并将其保存到模型和数据库中,或者不更新模型并显示错误消息。如果出现错误,用户输入会保留在 UI 中,供用户更正。但是应用程序的其他部分都看不到它。并且您有一个取消按钮,它只会丢弃包含编辑控件的视图部分 - 模型仍然有效且未更改。

现在有了数据绑定和 ViewModels 只暴露来自 Model 类的数据,在 TextBox 中输入的内容会立即进入模型,无论正确与否。IDataErrorInfo 仅此而已 - 信息。你可以认为它或忽略它。唯一强制执行的硬验证是类型转换:您永远不能将非数字字符串更新为数字模型字段。但仅此而已。我将通过让 ViewModel 进行所有验证并从属性设置器对无效数据抛出异常来解决这个问题。这是实现已知行为的唯一方法。

但是数据的保存和丢弃去哪里了呢?我什么时候才能真正将数据写回数据库?每次离开 TextBox 是否都会导致数据库写入,以便我不再需要显式保存命令(并且只能通过撤消恢复)?我什么时候会验证整个数据记录?我将如何处理模型和数据库不同步,由于数据绑定,无效输入立即传播到整个应用程序和所有视图?何时以及如何使用“取消”按钮丢弃任何用户输入,保持模型不变 - 或将其恢复到打开该编辑器对话框之前的状态?

我觉得 MVVM 没有为这些基本问题提供解决方案。我只是想念他们还是他们真的不存在?如果 MVVM 不是解决此问题的方法,那么什么是?或者 MVVM 最好不要用于 WPF 中的数据编辑应用程序?

pet*_*bil 6

MVVM 不会为您解决这些问题 - 您可以灵活地(能力?负担?)以您选择的任何方式解决数据库写入问题。如果您需要在保存回数据库之前收集所有数据,您可以这样做 - 只需在 ViewModel 上添加一个绑定到 SaveCommand 的 Save 按钮,该按钮执行您的数据访问存储过程/实体框架更新方法/任何内容。如果您想单独记录每一位数据,那么您需要在其他地方调用数据访问过程(可能是视图模型上的属性设置器?)

从本质上讲,MVVM 不是一个完整的端到端软件模式。它只关注用户看到的内容(列表框、文本框和按钮)与应用程序本身之间的通信。您的数据访问代码、序列化、存储、持久性,无论您使用什么以及以何种方式使用它,都保存在应用程序的 MVVM 端之后,在您的应用程序代码(模型)中。你可以随心所欲地写这个。

我目前正在编写一个应用程序,其中用户填写表单并点击保存或取消。Save 和 Cancel 都是绑定到 ViewModel 上的命令的按钮。在 ViewModel 构造函数中,模型对象的属性被复制到 ViewModel 的属性中。在保存时,ViewModel 的属性被复制回模型的属性并启动数据访问代码。在取消时,模型的属性被复制回 ViewModel 的属性。

class MyViewModel
{
   public MyViewModel(MyModel model)
   {
      this.Name = model.Name;
      this.Colour = model.Colour;
   }

   public string Name {get;set;}
   public string Colour {get;set;}

   // commands here that connect to the following methods

   public void Save()
   {
      model.Name = this.Name;
      model.Colour = this.Colour;
      model.SaveToDatabase();
   }

   public void Cancel()
   {
      this.Name = model.Name;
      this.Colour = model.Colour;
   }

}
Run Code Online (Sandbox Code Playgroud)

这是一种简单的方法 - 当然,您需要投入INotifyPropertyChanged其他部分,还有其他选择。但是我发现这种方法很容易理解正在发生的事情,并且是添加您可能需要添加的任何其他内容的良好基础。