Windows Forms Presentation Model Implementation

As mentioned last time, the Presentation Model pattern allows us to decouple our UI Model from our domain model. Briefly restated, this is a good thing, as we do not want UI concerns to leak into our domain model, and we also don’t want our View to contain a lot of logic, as these classes are typically difficult to test and maintain.

This article is going to walk through the code for a really simple example. All we are doing is displaying information about a single book including some extracts from the book. Without further ado, the code for the PresentationModel:

   public class BookPresentationModel : INotifyPropertyChanged
    {
        private readonly IBookService _service;
        private Book _book ;

        public BookPresentationModel(IBookView view, IBookService service)
        {
            _service = service;
            view.SaveChanges += SaveChanges;
        }

        public void Initialise(int bookId)
        {
            _book = _service.LoadBook(bookId);
        }

        public void Initialise(Book book)
        {
            _book = book;
        }

        public string BookName
        {
            get { return _book.Title; }
            set
            {
                _book.Title = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Title"));
            }
        }

        public string ISBN
        {
            get { return _book.ISBN; }
            set
            {
                _book.ISBN = value;
                PropertyChanged(this, new PropertyChangedEventArgs("ISBN"));
            }
        }

        public string Extract1
        {
            get
            {
                if (_book.Extracts[0] == null)
                    return string.Empty;
                return _book.Extracts[0];
            }
            set
            {
                _book.Extracts[0] = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Extracts"));
            }
        }

        public string Extract2
        {
            get
            {
                if (_book.Extracts[1] == null)
                    return string.Empty;
                return _book.Extracts[1];
            }
            set
            {
                _book.Extracts[1] = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Extracts"));
            }
        }

        private void SaveChanges(object sender, EventArgs e)
        {
            Console.WriteLine("Saving...");
            _service.Save(_book);
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
    }
  • The constructor of the PresentationModel class takes all the dependencies the class relies on. In this case, a service which can retrieve information about the book (perhaps to a database), and an instance of the view interface. These will need to be provided via the caller, and ideally via a Dependency Injection container such as Castle Windsor, Unity or StructureMap.
  • The class has a number of properties which encapsulate the domain object. This can flatten or transform the domain object for UI concerns. In our example, The book extracts are pulled out of the list by index, which is easier to bind to a pair of textboxes.
  • If the mapping between domain model and presentation model is more complex, it may be appropriate to have a mapper class that performs this operation. It might be possible to useĀ AutoMapper to perform this, although I haven’t investigated this yet – perhaps a future post.
  • We implement INotifyPropertyChanged and implement it’s single event – PropertyChanged. This event is called in the setter of each property and is required to support binding to controls, especially grids. Notice the empty delegate on the penultimate line, which means we don’t need to perform a null check before raising the event, as it’s invocation list will always contain at least one entry.
  • Events in the view are bound to a method in the Presentation Model between it and the view.
  • The initialise method is called by the caller to either pass an existing Book instance, or a book id to load from the service.

Any comments or suggestions more than welcome.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
This entry was posted in UI, Windows Forms and tagged , , . Bookmark the permalink.