Click here to Skip to main content
Email Password   helpLost your password?

Introduction

This article examines a way to easily transform data model objects into ViewModel objects, and safely add them to an observable collection, without introducing awkward assembly dependencies into an application. The technique makes use of generic delegates and the SynchronizationContext to maintain loose coupling between assemblies. This approach to transforming data types is applicable outside the realm of WPF and the Model-View-ViewModel (MVVM) pattern, but the article focuses on its use within a WPF application built using MVVM.

I nicknamed this technique “From Russia with Love” because it allows you to conveniently receive UI-friendly objects from a foreign, distant place in your application.

Background

This article assumes that the reader is familiar with building WPF applications based on the Model-View-ViewModel design pattern. The demo application, which is available for download at the top of this article, makes use of the ObservableObject and RelayCommand classes from my MVVM Foundation library on CodePlex. The MVVM Foundation DLL is included in the demo project.

The problem

When building an application structured according to the MVVM design pattern, it is often useful and necessary to have the Model and ViewModel types live in different assemblies. The classes that retrieve data objects (i.e. Model objects) often live in an assembly that has no knowledge of or access to the application’s ViewModel types. The ViewModel classes have intimate knowledge of the Model classes, and usually issue requests to classes that retrieve and instantiate Model data. Thus, the assemblies in which ViewModel classes reside reference the assemblies in which Model classes reside, but not vice versa.

This configuration is a natural and expected side-effect of the MVVM design pattern, wherein the Model classes represent the “pure” domain of the system being developed, and the ViewModel is an adapter between a user interface (UI) and the data model. A consequence of this setup is that the ViewModel classes are often burdened with the task of creating ViewModel objects that contain one or more Model objects. The logic that performs this task can easily lead to code bloat in the ViewModel classes, and can give them too much “code gravity” – which means that more and more code will end up being added to the ViewModel classes as time goes on.

A preferable solution would spread out the task of transforming Model objects into ViewModel objects across the parties involved, such that each party would contain reusable code responsible for the work most appropriate to it. Of course, using the term “most appropriate” indicates that this decision is open to interpretation. For the remainder of this article, I will examine a design that satisfies my opinion of how to best solve this problem. If your application’s needs are not met by the choices presented herein, you are free to abandon my approach and adopt that which best suits your specific needs.

Before moving forward, let’s first review the problem in more detail. What follows is a list of requirements that must be met by the solution:

An Example of the Problem

Suppose the Model assembly contains a Person class:

/// <summary>
/// Model class that represents a person.
/// </summary>
public class Person
{
    public Person(string firstName, string lastName)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
    }
    public string FirstName { get; private set; }
    public string LastName { get; private set; }
}

Now imagine that the UI needs to display Person objects in a list, where a button represents each person, and clicking a button causes the application to “select” that person (what selection means in this context is irrelevant to the discussion).

MainWindow.png

Each button in the UI executes a command referenced by its Command property upon being clicked. This means that each Person data object needs to somehow be associated with a command object, so that when a button is clicked its command knows which person was selected. To satisfy that requirement of this application, let’s create a CommandViewModel class:

public class CommandViewModel
{
    public CommandViewModel(ICommand command, string displayName, object commandParameter)
    {
        this.Command = command;
        this.DisplayName = displayName;
        this.CommandParameter = commandParameter;
    }
    public ICommand Command { get; private set; }
    public object CommandParameter { get; private set; }
    public string DisplayName { get; private set; }
}

All of the CommandViewModels are stored by one CommunityViewModel object (a class that represents a community of people), inside of its MemberCommands collection.

/// <summary>
/// Returns a read-only collection of command objects, each of which represents a 
/// member of the community.  When a command executes, it 'selects' the associated member.
/// </summary>
public ReadOnlyObservableCollection<CommandViewModel> MemberCommands{ get; private set; }

Now let’s see how the UI displays a collection of these CommandViewModel objects:

<ItemsControl ItemsSource="{Binding}">
    <ItemsControl.DataContext>
        <CollectionViewSource Source="{Binding Path=MemberCommands}">
            <CollectionViewSource.SortDescriptions>
                <scm:SortDescription PropertyName="DisplayName" />
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>
    </ItemsControl.DataContext>    
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button
                Command="{Binding Command}"
                CommandParameter="{Binding CommandParameter}"
                Content="{Binding DisplayName}"
                Margin="4"
                />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

At this point we know about the data model (the Person class) and the View and ViewModel (an ItemsControl that displays each CommandViewModel in the MemberCommands property of a CommunityViewModel). Now we need to determine how these two pieces of the application are tied together. The CommunityViewModel class needs to somehow retrieve the Person objects and populate its MemberCommands collection with CommandViewModels that represent each Person.

The Solution

A method in the Model assembly that retrieves Person data can be passed a delegate that takes a Person parameter, and returns a CommandViewModel object. However, since the Model assembly cannot have a reference to the ViewModel assembly, one might expect this to lead to a compiler error because the Model assembly cannot reference ViewModel types. This problem can be solved via the use of generic delegates. Since the return type of the delegate can be left unspecified as a generic type parameter, the Model assembly can successfully compile even though it is being used to create ViewModel types of which it has no knowledge.

Here is PersonDataSource, from the Model assembly, which is used to perform this task:

public class PersonDataSource
{
    public void RetrieveAndTransformAsync<TOutput>(
        ObservableCollection<TOutput>   output, 
        Func<Person, TOutput>           transform, 
        Action                          onCompleted)
    {
        if (output == null)
            throw new ArgumentNullException("output");
        if (transform == null)
            throw new ArgumentNullException("transform");

        // One possible improvement would be to create an overload of this method that
        // has a SynchronizationContext parameter, so it can be invoked on any thread.
        var syncContext = SynchronizationContext.Current;
        if (syncContext == null)
            throw new InvalidOperationException("...");

        ThreadPool.QueueUserWorkItem(delegate
        {
            try
            {
                // Fetch the data objects.
                var payload = RetrievePeople();

                // Transform each data object and add it to the output collection, 
                // on the UI thread.
                if (payload != null)
                    syncContext.Post(
                      arg => CreateOutput(payload, output, transform, onCompleted), null);
            }
            catch
            {
                // Implement error processing here...
            }
        });
    }

    static void CreateOutput<TPayload, TOutput>(
        IEnumerable<TPayload>           payload,
        ObservableCollection<TOutput>   output,
        Func<TPayload, TOutput>         transform,
        Action                          onCompleted)
    {
        foreach (TPayload dataItem in payload)
        {
            TOutput outputItem = transform(dataItem);
            output.Add(outputItem);
        }

        if (onCompleted != null)
            onCompleted();
    }

    static Person[] RetrievePeople()
    {
        // Simulate network latency for the demo app...
        Thread.Sleep(2500);

        // In a real app this would call an external data service.
        // The data access call would not have to be async, because
        // this method is executed on a worker thread.
        return new Person[]
        {
            new Person("Franklin", "Argominion"),
            new Person("Douglas", "Mintagissimo"),
            new Person("Mertha", "Laarensorp"),
            new Person("Zenith", "Binklefoot"),
            new Person("Tommy", "Frankenfield"),
        };
    }
}

The PersonDataSource class provides support for both data retrieval and transformation. The logic for transforming each Person into a ViewModel object is given to it via the transform delegate, which is a parameter of the RetrieveAndTransformAsync method. Notice that it uses the current SynchronizationContext to marshal back to the UI thread, instead of using WPF’s Dispatcher, in case this code must be eventually used to support other UI platforms. I intentionally omitted any error handling logic, because that kind of code can vary a lot across different applications.

Now it’s time to see how the CommunityViewModel, back in the main EXE assembly, uses the PersonDataSource class.

public CommunityViewModel()
{
    _memberCommandsInternal = new ObservableCollection<CommandViewModel>();
    this.MemberCommands = 
       new ReadOnlyObservableCollection<CommandViewModel>(_memberCommandsInternal);

    // Create the command that is used by each CommandViewModel in MemberCommands.
    _selectMemberCommand = new RelayCommand<Person>(this.SelectMember);

    // Create the data source and begin a call to fetch and transform Person objects.
    var dataSource = new PersonDataSource();
    dataSource.RetrieveAndTransformAsync(
        _memberCommandsInternal,         // output
        this.CreateCommandForPerson,     // transform
        () => this.IsLoadingData = false // onCompleted
        ); 

    this.IsLoadingData = true;
}

void SelectMember(Person person)
{
    // In a real app this method would do something with the selected Person.
    string msg = String.Format("You selected '{0}'.", FormatName(person));
    MessageBox.Show(msg, "Congratulations!");
}

CommandViewModel CreateCommandForPerson(Person person)
{
    return new CommandViewModel(_selectMemberCommand, FormatName(person), person);
}

static string FormatName(Person person)
{
    return String.Format("{0}, {1}", person.LastName, person.FirstName);
}

Notice how CommunityViewModel only contains the logic necessary to wrap a Person in a CommandViewModel, as seen in its CreateCommandForPerson method. It does not need to handle the completion of the data access call, check for errors, marshal execution back to the UI thread, and iterate over the list of Person objects. All of that repetitive post-processing code has been conveniently consolidated in PersonDataSource. I find this separation of concerns to strike the right balance between having the ViewModel classes do too much versus having the Model classes know too much.

Revision History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralCommands and the ViewModel
Marc Schluper
6:13 4 Dec '09  
Could the ViewModel exist without any commands, like in Why I Love Silverlight Data Binding[^]? In my (current) understanding of MVVM its main benefit is that it allows the Views to reflect the state of the data "automatically," using TwoWay data binding. The emphasis put on commands (and an empty code-behind) seems a distraction to me.

Marc Schluper
Beaverton, OR

GeneralRe: Commands and the ViewModel
Josh Smith
6:25 4 Dec '09  
Marc Schluper wrote:
ould the ViewModel exist without any commands


Yes.

Marc Schluper wrote:
The emphasis put on commands (and an empty code-behind) seems a distraction to me.


You can't please everybody. If I made the demo too simple, other people would have left comments saying that it isn't "real world" enough. Roll eyes

:josh:
Try Crack![^]
Sleep is overrated.

GeneralSynchronizing the ViewModel collection with the Model collection
ian_duncanson
20:00 2 Dec '09  
Josh,

This may be slightly off-topic, but is related to your sample - do you know of any good pattern to keep collections in the ViewModel synchronized with changes to the Model? So when an element is added to or removed from a collection in the Model (in your sample, the Person[]), the corresponding ViewModel collection also gets updated (in your sample _memberCommandsInternal).

Thanks,
Ian
GeneralAdvantages
Asher Barak
4:15 3 Nov '09  
Hi Josh,

How would this approch be foundemetaly different than creating VM's on another VM, in the VM layer?
After all, you will alway have to have the "Wrap this V in a VM" code in the VM layer.

Why is creating the list of Persons VM's not a mission for the VM layer?

Asher
GeneralRe: Advantages
Josh Smith
6:19 3 Nov '09  
Good question, Asher. This approach is basically the same as creating the VMs in another "layer" of the VM. The key point is creating the VMs in a place separate from the VM objects. The advantages of this are that the VM objects are not burdened with repetitive Data Model object iteration, wrapping, error checking, etc. I like to put this logic into the DataModel/DataAccess layer because it does not introduce another layer, as your question implied. But, the location of such code is not that important, as long as it isn't spread out all over the various VM classes.

:josh:
Try Crack![^]
Sleep is overrated.

GeneralGreat article and rather entertaining :-)
DrABELL
16:50 16 Sep '09  
Hi Josh:

I like reading your article. Great stuff, indeed!
Kudos and 5*.

My best,

Alex
GeneralRe: Great article and rather entertaining :-)
Josh Smith
18:54 16 Sep '09  
Thanks!

:josh:
Try Crack![^]
Sleep is overrated.

GeneralMust have missed this one
Sacha Barber
5:18 16 Sep '09  
Good to see you back. Have a 5

Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralRe: Must have missed this one
Josh Smith
5:18 16 Sep '09  
Thank you, kind sir.

:josh:
Try Crack![^]
Sleep is overrated.

GeneralA good article
Steve Solomon
22:44 14 Sep '09  
You are indeed the man with the golden mouse!

This offers a simple and yet powerful method for prodcucing ViewModels from an Model. It allows great flexibility in that the Model can then produce different ViewModels simply by being passed a different delegate, but by making use of the of same dataaccess functionality each time. This is especially good if the Person data is subsequently cached. A 5 from me. Does this mean you now wish to be know as Q
GeneralRe: A good article
Josh Smith
7:51 15 Sep '09  
Thanks Steve.

Steve Solomon wrote:
Does this mean you now wish to be know as Q


Hmm...I think "Josh" will do. Smile

:josh:
Try Crack![^]
Sleep is overrated.

GeneralExample with typed datasets
lucho_1981
9:16 11 Sep '09  
Hello Josh

First of all thanks a lot for the valuable information, there are very few LOB examples out there utilizing wpf. I have a little challenge for you utilzing your desing patterns. so here it goes

How about a closer to reality case, lets say a typed dataset that has multiple tables (6 or more) with relationships representing a hierarchy, and we would like to have a treeview docked on the left and 3 datagrids docked to the right that represent the next 3 tables in the hierarchy. This datagrids must react to each other selections accordingly in a Grand Parent, Child, Grand child manner (same as master / detail / detail' details)

How would you go about creating view models that handles all this. I have been able to create the treeview and the Grand Parent datagrid. But when it comes to creating the Child/ and grand child datagrids. I have not been able to bind them correctly to the view model and at the same time to make them react properly to each other selections. Remember that this datagrids represent completely different tables depending on the treeview selection.
GeneralThis is "Quantam of Solace" Josh! [modified]
Visu.v
20:57 9 Sep '09  
gr8 article Josh...My 5

Can you also please share the real time scenario which actually prompted you to come up with such a solution? I think this will enable a reader to actually realize the situations in which this implementation can be used. just a thought.

Visu

http://mywpf-visu.blogspot.com/[^]

modified on Thursday, September 10, 2009 2:06 AM

GeneralRe: This is "Quantam of Solace" Josh!
Josh Smith
6:30 10 Sep '09  
Visu.v wrote:
Can you also please share the real time scenario which actually prompted you to come up with such a solution? I think this will enable a reader to actually realize the situations in which this implementation can be used. just a thought.


The app I'm working on pulls data down from a remote server, and we need the UI to fill up with that data whenever it becomes available on the client. By having the data access code handle the Model to ViewModel transformation, and populate an observable collection once the data arrives, it simplifies the ViewModel development. Sorry, I can't get into more specifics than that, because of the secretive nature of the project.

:josh:
Try Crack![^]
Sleep is overrated.

GeneralSilly question time
Mycroft Holmes
23:36 8 Sep '09  
Having read through this and your MSDN article and having no experience with WPF yet, I have an issue.

All your focus for the command object/list is to bind a command to a data object, does that model support binding where toolstrip buttons (obviously I'm from a winforms background) would activate the AED command AND/OR a double click on the item would activate the edit command.

I seem to have lost my voting rights at the moment - expect another 5 when they are reinstated.


GeneralRe: Silly question time
Josh Smith
6:30 9 Sep '09  
Sorry, I don't understand your question. Please rephrase it.

:josh:
Try Crack![^]
Sleep is overrated.

GeneralRe: Silly question time
Mycroft Holmes
13:43 9 Sep '09  
I did warn you that it wa sa silly question!

In your demo UI you use an event on each data item to initiate a process, binding it back to a command in a list. Ah click in your MSND article you bind the create customer to the left panel, so I am talking about the createnewcustomer command that is bound to the workspace list rathat than the AED command bound to the data item.

Thank you for clearing that up, I'm glad we had this discussion.

Never underestimate the power of human stupidity
RAH

GeneralGreat Post - What if you change a person's name, will the ViewModel's DisplayName update?
Tawani Anyangwe
8:15 8 Sep '09  
I'm just wondering, how will you handle a situation where a Model's property value is changed at runtime. Will the corresponding view model also update the necessary bindings?

        void SelectMember(Person person)
{
// In a real app this method would do something with the selected Person.
string msg = String.Format("You selected '{0}'.", FormatName(person));
person.LastName = DateTime.Now.ToString();
MessageBox.Show(msg, "Congratulations!");
}

GeneralRe: Great Post - What if you change a person's name, will the ViewModel's DisplayName update?
Josh Smith
8:35 8 Sep '09  
The Person class would need to implement INotifyPropertyChanged and raise the PropertyChanged event when the name changed (or provide the CommunityViewModel with some other means of knowing when the LastName changed).

:josh:
Try Crack![^]
Sleep is overrated.

GeneralRe: Great Post - What if you change a person's name, will the ViewModel's DisplayName update?
Tawani Anyangwe
8:47 8 Sep '09  
It would be cool to implement some kind of generic PropertyObserver (e.g. in CreateOutput<TPayload, TOutput>) to watch the model, if any property changes, then reload the ViewModel automatically.
GeneralRe: Great Post - What if you change a person's name, will the ViewModel's DisplayName update?
Josh Smith
9:06 8 Sep '09  
Are you familiar with the PropertyObserver class in MVVM Foundation[^]?

:josh:
Try Crack![^]
Sleep is overrated.

GeneralRe: Great Post - What if you change a person's name?
Tawani Anyangwe
9:14 8 Sep '09  
Yes, I am. That's what I was referring to.
What will be the best approach to implement it in the CommunityViewModel's CreateCommandForPerson method so that we can watch for changes to the person's name?


        CommandViewModel CreateCommandForPerson(Person person)
{
PropertyObserver<Person> target = new PropertyObserver<Person>(person);
target.RegisterHandler(t => t.LastName, t => FormatName(t));

return new CommandViewModel(_selectMemberCommand, FormatName(person), person);
}

GeneralRe: Great Post - What if you change a person's name?
Josh Smith
9:57 8 Sep '09  
You would also have to make CommandViewModel implement INotifyPropertyChanged (or derive from ObservableObject), because that is what the UI is actually binding to. The DisplayName property would have to be updated when the Person's name properties change, and PropertyChanged would be raised for DisplayName.

:josh:
Try Crack![^]
Sleep is overrated.

GeneralTetris
aspdotnetdev
16:02 7 Sep '09  
When I read the title, I thought you were referencing Tetris, not Bond: http://en.wikipedia.org/wiki/Alexey_Pajitnov[^] (search the page for "from russia")

Oh well, I'm pretty sure I saw another WPF Tetris article around here somewhere... Poke tongue

Visual Studio is an excellent GUIIDE.

GeneralRe: Tetris
Josh Smith
20:06 7 Sep '09  
WPF Tetris...now that would be fun! I once wrote Tetris in WinForms and had a blast making it. Thanks for the idea... Big Grin

:josh:
Try Crack![^]
Sleep is overrated.


Last Updated 7 Sep 2009 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010