Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Generic MVVM Data Exchange between Model and ViewModel

5.00/5 (4 votes)
31 Jul 2019CPOL2 min read 18.2K  
Make data exchange in MVVM easy on yourself

Introduction

I've been developing a tool to help the other devs on the team deal with the creation of menu items for their MVC apps. The tool in question is a WPF desktop app that utilizes the MVVM pattern. I was writing the models and associated view models when it struck me that I'd been doing it "the hard way" all these years. I was writing a series of methods *in every viewmodel* that shuttled data back and forth between the model and the view model. For some of the models, this involved 20 or more properties, and the coding required to support them was pure drudgery. Yesterday, I came up with an alternative.

The Code

I created a class with the following code, and inherited that class from my view model classes:

C#
public enum MVVMDirection { FROM, TO };

/// <summary>
/// ViewModel base class
/// </summary>
public class VMBase
{
    /// <summary>
    /// Move the data from the model to the viewmodel, using reflection. 
    /// Property names in both objects MUST be the same (both name and type)
    /// </summary>
    /// <typeparam name="TModel">The model's type</typeparam>
    /// <param name="model">The model object the data will be moved from</param>
    public void UpdateFromModel<TModel>(TModel model)
    {
        this.Update<TModel>(model, MVVMDirection.FROM);
    }

    /// <summary>
    /// Move the data from the viewmodel to the model, using reflection. 
    /// Property names in both objects MUST be the same (both name and type)
    /// </summary>
    /// <typeparam name="TModel">The model's type</typeparam>
    /// <param name="model">The model object the data will be moved from</param>
    public void UpdateToModel<TModel>(TModel model)
    {
        this.Update<TModel>(model, MVVMDirection.TO);
    }

    /// <summary>
    /// Update to or from the model based on the specified direction. Property names in both 
    /// objects MUST be the same (both name and type), but properties used just for the view 
    /// model aren't affected/used.
    /// </summary>
    /// <typeparam name="TModel">The model's type</typeparam>
    /// <param name="model">The model object the data will be moved to/from</param>
    /// <param name="direction">The direction in which the update will be performed</param>
    public void Update<TModel>(TModel model, MVVMDirection direction)
    {
        PropertyInfo[] mProperties  = model.GetType().GetProperties();
        PropertyInfo[] vmProperties = this.GetType().GetProperties();

        foreach(PropertyInfo mProperty in mProperties)
        {
            PropertyInfo vmProperty = this.GetType().GetProperty(mProperty.Name);
            if (vmProperty != null)
            {
                if (vmProperty.PropertyType.Equals(mProperty.PropertyType))
                {
                    if (direction == MVVMDirection.FROM)
                    {
                        vmProperty.SetValue(this, mProperty.GetValue(model));
                    }
                    else
                    {
                        vmProperty.SetValue(model, mProperty.GetValue(this));
                    }
                }
            }
        }
    }
}

Example Usage

As with any code, there is more than one way to use these methods. In my own case, my typical ViewModel object contains a property that represents the model, and the constructor takes a model object parameter. After setting the Model property from the parameter, the constructor performs an initial call to the UpdateFromModel() method. My view models look something like this:

C#
// ViewModelBase contains the methods that are discussed in this tip, 
// and in my case, ViewModelBase inherits from 
// a class called Notifiable which inherits from INotifyPropertyChanged 
// and contains properties to support using view 
// models in a WPF environment.
public partial class MyViewModel : ViewModelBase 
{
    private string property1;

    public MyModel Model { get; set; }

    public string Property1 
    { 
        get { return this.property1; }
        set
        {
            if (this.property1 != value)
            {
                this.property1 = value;
                // in the "Notifiable" class
                this.NotifyPropertyChanged();
            }
        }
    }

    public MyViewModel(MyModel model)
    {
        this.Model = model;
        // in the ViewModelBase class
        this.UpdateFromModel<mymodel>(this.Model);
    }
}

I use a Model property because I don't want to commit changes to the model's data until the user is ready to do so (determined by actions in the UI). Of course, you could directly update the model's value from the viewmodel property (via app UI actions) if that's what you need to do, but that's not the way *I* do it. As for the data transfer between object properties, you can likely imagine a long list of this kind of code, you can probably understand why I came up with these base class methods.

I understand that some of you reading this may have a different outlook on life as it relates to where you put code and how you implement the MVVM pattern, so here's an example of doing it a little different, you can also perform that initial method call externally of the viewmodel object after instantiating the view model, like so:

C#
// create and populate your model however you want/need to do it
MyModel modelObj = new MyModel();

// do something to populate your model if necessary (my model objects are 
// created and populated via calls to the database)

// create your viewmodel
VMMyModel vmObj = new VMMyModel();
// and move the model data to the viewmodel
vmObj.UpdateFromModel<MyModel>(modelObj);

// change the viewmodel property values
// and then move it back to the model
vmObj.UpdateToModel<MyModel>(modelObj);

// save your model to the data source from which it was retrieved
modelObj.CallYourSaveMethod();

I can't possibly conjure up a definitive list of use cases, and I'm honestly not interested in religious discussions regarding implementation styles, so I hope you get the idea of how to utilize the code. Go forth, and mould it into your own image.

Change History

  • 2019.08.03 - Fixed the Update method to remove references to the viewmodel parameter

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)