Saving New or Edited Cars
In this step you will add the functionality to save a new or edited car to the database and expose commands for the view to bind to. You will need to implement the required methods and expose command objects based on them.
Implementing the required methods
-
In the constructor add a call to a method which will be defined shortly - InitializeCurrentCarAndTitle.
this.InitializeCurrentCarAndTitle();
Me.InitializeCurrentCarAndTitle()
-
Create a new method called InitializeCurrentCarAndTitle. This model will initialize currentCar and title depending on wheter a car Id has been passed to the view model`s constructor. If a car Id has been passed, the view model is in edit mode, if there is no car Id, the view model is in add mode.
private void InitializeCurrentCarAndTitle() { if (this.currentCarId.HasValue) { //The view model is in Edit mode this.CurrentCar = this.context.Cars.FirstOrDefault(car => car.CarID == this.currentCarId.Value); this.Title = EDIT_MODE_TITLE; } else { //The view model is in Add mode this.CurrentCar = new Car() { Latitude = 0.000000d, Longitude = 0.000000d }; this.Title = ADD_MODE_TITLE; } if (this.CurrentCar.CarYear.HasValue == false) { this.CurrentCar.CarYear = (short)DateTime.Now.Year; } }
Private Sub InitializeCurrentCarAndTitle() If Me._currentCarId.HasValue Then 'The view model is in Edit mode Me.CurrentCar = Me._context.Cars.FirstOrDefault(Function(car) car.CarID = Me._currentCarId) Me.Title = EDIT_MODE_TITLE Else 'The view model is in Add mode Me.CurrentCar = New Car() With {.Latitude = 0D, .Longitude = 0D} Me.Title = ADD_MODE_TITLE End If If Me.CurrentCar.CarYear.HasValue = False Then Me.CurrentCar.CarYear = DateTime.Now.Year End If End Sub
-
Add a new method called Save. This method will add the CurrentCar object in the database if the view model is in add mode or save the changes made to CurrentCar if the view model is in edit mode.
private void Save() { if (this.currentCarId.HasValue == false) { //Add the new car to the context this.context.Add(this.CurrentCar); } try { if (this.context.HasChanges) { this.context.SaveChanges(); } this.OperationIsSuccessful = true; } catch (DataStoreException ex) { this.HandleException(ex.BackendError.Description); return; } catch (DuplicateKeyException ex) { this.HandleException(ex.BackendError.Description); return; } catch (Exception ex) { this.HandleException(ex.Message); return; } }
Private Sub Save() If Me._currentCarId.HasValue = False Then 'Add the new car to the context Me._context.Add(Me.CurrentCar) End If Try If Me._context.HasChanges Then Me._context.SaveChanges() End If Me.OperationIsSuccessful = True Catch ex As DataStoreException Me.HandleException(ex.BackendError.Description) Exit Sub Catch ex As DuplicateKeyException Me.HandleException(ex.BackendError.Description) Exit Sub Catch ex As Exception Me.HandleException(ex.Message) Exit Sub End Try End Sub
-
Create the HandleException method. It is called from Save() and takes as an argument the exception message which should be displayed. Displays a message box with information about the occurred error, and causes the view`s controls displaying information about the car to rebind.
private void HandleException(string exceptionMessage) { MessageBox.Show(SAVE_ERROR_MESSAGE + exceptionMessage, SAVE_ERROR_TITLE, MessageBoxButton.OK, MessageBoxImage.Error); this.OperationIsSuccessful = null; //Cause binding refresh this.RaisePropertyChanged("CurrentCar"); }
Private Sub HandleException(exceptionMessage As String) MessageBox.Show(SAVE_ERROR_MESSAGE + exceptionMessage, SAVE_ERROR_TITLE, MessageBoxButton.OK, MessageBoxImage.Error) Me.OperationIsSuccessful = Nothing 'Cause binding refresh Me.RaisePropertyChanged("CurrentCar") End Sub
-
Create a method called Cancel. Here you should call the Close method of the related view.
private void Cancel() { this.View.Close(); }
Private Sub Cancel() Me.View.Close() End Sub
Exposing commands to the the view
Now you need to expose commands based on the methods Save and Cancel to the view.
-
Create a property called SaveCommand. In its getter, initialize a RelayCommand object based on the Save method and return it.
public RelayCommand SaveCommand { get { this.command = new RelayCommand(this.Save); return this.command; } set { this.command = value; } }
Public Property SaveCommand As RelayCommand Get Me._command = New RelayCommand(AddressOf Me.Save) Return Me._command End Get Set(value As RelayCommand) Me._command = value End Set End Property
-
Create a property called CancelCommand. In its getter, initialize a RelayCommand object based on the Cancel method and return it.
public RelayCommand CancelCommand { get { this.command = new RelayCommand(this.Cancel); return this.command; } set { this.command = value; } }
Public Property CancelCommand As RelayCommand Get Me._command = New RelayCommand(AddressOf Me.Cancel) Return Me._command End Get Set(value As RelayCommand) Me._command = value End Set End Property
Disposing the context
-
In AddEditViewModel implement the IDisposable interface to make it disposable. In the Dispose method, dispose the OpenAccessContext object. This way when the view model is no longer needed and thus disposed, the context will be disposed as with it.
public void Dispose() { //The context is local to the ViewModel and must be disposed together with it if (this.context != null) { this.context.Dispose(); } }
Public Sub Dispose() Implements IDisposable.Dispose 'The context is local to the ViewModel and must be disposed together with it If IsNothing(Me._context) = False Then _context.Dispose() End If End Sub