Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does validating and saving data in WPF MVVM work right?

I am new to MVVM (and a bit of WPF) and I've read many Code Project articles, blog posts and Stackoverflow questions in the last few days. I have the impression that data binding works really nice to display data once loaded from a data source (database) and to keep the model in sync with the view, also updating all other appearances of the model data in the view(s).

But I still have no real clue how saving, and before that validating, is supposed to work right. I have a strong Windows Forms and ADO.NET background. I am well familiar with coding both the database access layer and the view updating. Back then, you had temporary, scratch data, being edited, only in the view, and the last saved version of the data in the model classes and the database. The model classes were usually in sync with the database. It was the view that contained the data that was not saved yet.

You also had a Save button that would read all data from the controls, validate it in code and either accept and save it to the model and database, or not update the model and display an error message instead. In case of an error, the user input remained in the UI for the user to correct it. But no other part of the application could see it. And you had a Cancel button that would just throw away that part of the view that contains the editing controls - the model was still valid and unchanged.

Now with data binding and ViewModels just exposing data from the Model classes, what is entered in a TextBox immediately goes into the model, be it correct or not. IDataErrorInfo is nothing more than that - informational. You can regard it or ignore it. The only hard validation that is enforced is type conversion: you can never update a non-numeric string into a numeric model field. But that's about it. I'm going to solve that by letting the ViewModel do all validation and throw an exception from the property setter on invalid data. This is the only way to implement the known behaviour.

But where does saving and discarding of data go? When will I actually write data back to the database? Does every leaving of a TextBox cause a database write so that I won't need an explicit Save command anymore (and only get reverting through Undo)? When will I validate a whole record of data? How will I deal with the model and database being out of sync, with invalid input immediately propagating through the whole application and all views thanks to data binding? When and how can I discard any user input with a Cancel button, leaving the model unchanged - or reverting it to a state before that editor dialog was opened?

I feel like MVVM does not provide solutions to these elementary problems. Did I just miss them or do they really not exist? If MVVM is not a solution to this, then what is? Or should MVVM better not be used for data editing applications in WPF?

like image 935
ygoe Avatar asked Jul 06 '12 13:07

ygoe


2 Answers

MVVM doesn't answer these problems for you - you have the flexibility (power? burden?) to resolve database writing in any fashion you choose. If you need to collect all the data before you save back to the database, you can do that - just add a Save button bound to a SaveCommand on the ViewModel, which executes your data access stored procedure/entity framework update method/whatever. If you want to record each bit of data individually, then you'll need to call the data access procedures somewhere else (probably the property setters on the view model?)

Essentially, MVVM is not a complete end-to-end software pattern. It is only looking at the communication between what the user sees (listboxes, textboxes and buttons) and the application itself. Your data access code, serialisation, storage, persistance, whatever you are using and however you are using it is all held behind the MVVM side of the application, in your application code (the model). You can write this however you like.

I'm currently writing an application where a user fills out a form and hits Save or Cancel. Save and Cancel are both buttons bound to commands on the ViewModel. In the ViewModel constructor, the properties of a model object are copied to the properties of the ViewModel. On Save, the properties of the ViewModel are copied back to the model's properties and the data access code is initiated. On Cancel, the model's properties are copied back over the ViewModel's properties.

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;
   }

}

That's a simple way to do it - of course, you need to throw in INotifyPropertyChanged and the rest of it, and there are other options. But I find this method easy to understand what is going on and a good base to add anything else that you may need to chuck in.

like image 115
pete the pagan-gerbil Avatar answered Nov 14 '22 23:11

pete the pagan-gerbil


With MVVM, you bind controls in your view to properties and commands in your ViewModel. The Model represents your database.

Validation of user input can be done in several ways. You can restrict textboxes to only accept certain data, you can validate data in property setters etc etc.

I'm no database expert, but I would collect the information in my VM and add a save button somewhere in the view which validates data and writes it to the database. A cancel button could overwrite the VM properties with the (unchanged) values from the model (database).

(edit: what Pete says :)

like image 38
MrEdge Avatar answered Nov 14 '22 21:11

MrEdge