Posts Tagged ‘ MVVM ’

MVVM Enabling Database Driven Silverlight Applications

One of the more exciting projects we are working on here at Affirma is a line-of-business solution for a client that includes talking to a SQL Server backend.  This was a great opportunity to put our own MVVM framework to the test in developing a data-driven Silverlight client that would increase productivity and visibility for our customer.

There are a number of different topics from our lessons learned that could be covered in our blog, and I will definitely cover as many as possible in the future, but for now I just wanted to highlight how we were able to put together a group of technologies in a very quick timeframe to provide great value to our customers.

If you are unfamiliar with MVVM, don’t fret!  You can read this quick overview from Joel Wetzel on the topic to get a quick understanding, but for now just think of it as a group of patterns and practices wrapped into a framework that allows us to build testable and reusable components with great flexibility.  It’s also a topic we will cover in blog posts in the future.

For this project, we used the following technologies:

  • Microsoft SQL Server 2008
  • Silverlight 4 (including the Toolkit)
  • Silverlight Unit Testing Framework
  • Windows Communication Foundation
  • DevExpress Silverlight Controls
  • .NET 4.0, ASP.NET 3.5/4.0, RhinoMocks, nUnit, MSTest, and others

The requirement from our customer was to provide an interface for their managers to modify and insert business data in monthly batches that would then report up to business operations for accounting and other purposes.  The managers were also familiar with WPF clients and so Silverlight seemed like a great choice for their intranet needs.  To understand how all these pieces fit together, here is a pretty little architecture diagram.

Now for the tricky part.  Silverlight runs on the client UI thread and cannot talk directly to SQL or other server code that requires a network connection.  So how is this accomplished?  With a little asynchronous, anonymous delegate gravy!!

using System;
using System.Collections.Generic;
using Affirma.Silverlight.Services;

namespace SilverlightLOB.DomainServices
{
    public interface IDomainService : IClientService
    {
        void Add(BusinessObject businessObject, Action<IResult<bool>> action);
        void GetItemsFor(Store store, Action<IResult<IEnumerable<BusinessObject>>> action);
    }

    public class DomainService  : IDomainService
    {
        public void Add(BusinessObject businessObject, Action<IResult<bool>> action)
        {
			// our web service proxy
            var client = new DataServiceClient();

            client.AddCompleted +=
                (obj, args) =>
                {
                    if (args.Error != null)
                        Logging.Log.Debug("Error in Add - " + args.Error.Message);

                    action.Invoke(new SimpleServiceResult { Error = args.Error });
                };

            client.AddAsync(businessObject);
        }

        public void GetItemsFor(Store store, Action<IResult<IEnumerable<BusinessObject>>> action)
        {
            var client = new DataServiceClient();

            client.GetItemsForCompleted +=
                (obj, args) =>
                {
                    if (args.Error != null)
                        Logging.Log.Debug("Error in GetItemsFor - " + args.Error.Message);

                    var result = new EnumerableServiceResult<BusinessObject> {Error = args.Error};
                    if (result.Success)
                        result.Value = args.Result;

                    action.Invoke(result);
                };

            client.GetItemsForAsync(store);
        }
    }
}

Easy!  This domain service lives on the client UI thread and will execute asynchronous requests to our WCF service, and invoke the result back onto our UI thread thanks to the provided callback.  This means the Silverlight client UI can continue to execute requests and other user interactions while the service requests process and returns a value.  From our view model, we can easily wire up to this domain service and execute the appropriate asynchronous method.

public ICommand AddCommand
{
	return ConstructCommand(() => AddCommand, AddHandler);
}

void AddHandler()
{
	_service.Add(ObjectToInsert,
		result => {
			if (result.Success) MessageBox.Show("Success!");
		};
}

Undo/Redo and Encapsulated Data Changes in Silverlight

We’re currently working on a Silverlight application that needed a robust undo/redo system.  Every change a user could make to data needed to be able to be undone.  At Affirma, we have a set of tools we’ve built for Silverlight – using an MVVM and Service-Oriented pattern – but this was not a tool already in it!  No matter, the great thing about a tool like an undo/redo system is that it must be a general tool, and so it could be added to our toolkit for use on many projects.

The way we chose to go about making this system was to abstract out the idea of a “Change”.  In the abstract, a change would be an encapsulated something (also known as a class, but the dramatic form is fun) that knew how to alter data both forwards and backwards.  Okay, that’s pretty abstract, so how about an example.  Let’s say we have a DeleteChange that can remove a piece of data from a repository.  This DeleteChange would need to know what piece of data it had to delete, it would need a way to delete that data, it would need to keep track of that data so the change could be undone, and it would need a way to add the data back for an undo.

Okay, some code:

namespace Affirma.Silverlight.Changes
{
    public abstract class Change
    {}

    /// <summary>
    /// A change does and undoes work on a target.
    /// </summary>
    public abstract class Change<TargetType> : Change
        where TargetType : class
    {
        /// <summary>
        /// An implementation should override this method and do work on the target here.
        /// </summary>
        public abstract void Do(TargetType target);

        /// <summary>
        /// An implementation should override this method and undo work on the target here.
        /// </summary>
        public abstract void Undo(TargetType target);

        /// <summary>
        /// An implementation should override this method and notify any listeners of the change here.
        /// </summary>
        public abstract void Notify(TargetType target);

        /// <summary>
        /// An implementation should override this method to finalize doing and undoing the action here.
        /// </summary>
        /// <param name="target"></param>
        public abstract void Finalize(TargetType target);
    }
}

A few notes:

1 – You would make a child class for each type of change you might want to make to your data.

2 – The changes are strongly typed (through generics) to the data object they will act upon.

3 – You implement methods for doing the change and undoing it.

4 – We added a Notify method.  In practice, often other systems would need to know about the change, so this is where you could notify them.

5 – We often found that we needed to “preview” a change, but not finalize it.  An example would be dragging an element around the screen.  We might need to “test the waters” of the change as we drag the element around, but we don’t want to finalize the change until we drop the element.  That’s why we have a finalize method.

6 – You’re probably getting the feeling about now that this system requires some discipline.  It does.  You MUST NOT alter data anywhere but inside a change.  However, we found that in practice, using that discipline up front saved us a lot of time down the road.  We always knew where to look to find where the data changed.  Data changes weren’t hiding in corners of the system.  And there was fantastic encapsulation.  Clients shouldn’t know what it takes to change the data.  They usually shouldn’t even know about all the data!  They just know they want a change, and these classes encapsulate it.

Okay, so the next step.  We wrote a service (internal to the Silverlight application) to manage these changes.  Here’s the interface:

namespace Affirma.Silverlight.Services
{
    /// <summary>
    /// An IChangeManagerService is used to manage data changes in systems where undo/redo
    /// functionality is desired. It is a generic interface, and the generic type is the type of
    /// the target that all the changes will act upon.  Generally, the target will be the root
    /// of a model graph.  The changes act upon this target to do their work, undo it, and redo it.
    /// </summary>
    /// <typeparam name="TargetType">The type of the target that all the changes will act upon.  Generally, the target will be the root of a model graph.</typeparam>
    public interface IChangeManagerService<TargetType> : IClientService
        where TargetType : class
    {
        /// <summary>
        /// Registers the target for all the changes.  This must be done before changes can be done.
        /// </summary>
        /// <param name="target"></param>
        void RegisterTarget(TargetType target);

        /// <summary>
        /// Performs a change, but does not commit it yet.
        /// </summary>
        void PreviewChange(Change<TargetType> newChange);

        /// <summary>
        /// Commits the currently previewed change.  It will be added to the undo stack.
        /// </summary>
        void CommitChange();

        /// <summary>
        /// Previews and commits a change in one step
        /// </summary>
        void CommitChange(Change<TargetType> newChange);

        /// <summary>
        /// Undoes the previewed change.
        /// </summary>
        void CancelChange();

        /// <summary>
        /// Undoes the most recent change.
        /// </summary>
        void Undo();

        /// <summary>
        /// Redoes the most recently undone change.
        /// </summary>
        void Redo();
    }
}

Notes on this:

1 – Currently, this service only supports one target.  It could be expanded to have multiple targets and you would tell it what target the change should act upon.

2 – The interface is a higher abstraction than that of the changes.  For example, preview.  Previewing a change calls Do and Notify, but not Finalize.  If you preview a second time before finalizing, it calls, Undo on the old change, and then Do and Notify on the new one.  Finalize gets called when you commit the change.  This is to support the previously-mentioned drag-and-drop scenario.

3 – The ChangeManagerService keeps track of changes that have been done and undone in two stacks.  It support infinite undo, but we could put a limit in.

The end result of all this work:  Encapsulated Object-Oriented changes.  Do/Undo/Redo capability.  And the ChangeManagerService is ready and waiting for more projects!

Next time I’ll talk about an extra we just added to the ChangeManagerService.  Object-Oriented business rules. Awesome.

Silverlight and MVVM

All of Affirma Consulting’s Silverlight projects use the MVVM (Model-View-ViewModel) pattern.  This design pattern is modular, testable, and takes advantage of Silverlight’s powerful data-binding capabilities.

A selection of resources on MVVM and Silverlight:

5 Minute Overview of MVVM

MVVM Light Toolkit

Wikipedia Entry

You can find many, many more with a quick Google search and you’ll quickly learn that arrayed around the central MVVM pattern, people tend to use things like ServiceLocator patterns, variations on Observer or Signals And Slots to perform messaging between ViewModels, and that really no one completely agrees on what MVVM is.  That’s one thing you quickly discover.  There 8 dozen existing MVVM frameworks out there.  They each wire up the references in a different way.  And they each contain a different sampling of satellite features.

For example, what is a ViewModel?  Is it a view into the Model?  Maybe.  It certainly wraps the model data in a form that is useful for the view.  But more than that, it’s a model of the view.  The ViewModel maintains state for the View.  Anything in the View that can change should be bound to a property on the ViewModel.  But now the ViewModel is performing two jobs, which is a violation of singularity of purpose.  So we could split it in two and have a model wrapper and a view state machine.  There’s a reason no one does this.  It’s just too much make-work for the payoff.  When done well, our ViewModels tend to be pretty simple anyway.  Why create roadblocks between the view state and the model state?

This is just the first of many postings we’ll be making on MVVM.  Check back frequently for discussions of the intricacies.

%d bloggers like this: