Click here to Skip to main content
Click here to Skip to main content

The WPF-NHibernate Toolkit

, 16 Jan 2010
Rate this:
Please Sign up or sign in to vote.
Adapt NHibernate classes to run in WPF

Introduction

WPF is great--really. NHibernate is great, too. But they don't like each other—at all. At a recent Microsoft training class, the instructor was asked a question about using WPF with NHibernate. His response was “Yeah—good luck making that work!” Well, in this article, we're going to provide you with the skills and tools to make it work, and to make it easy to do so.

One of the greatest things about WPF is its data-binding capabilities. I don't know if WPF is actually Rev. 3 of data-binding, but Microsoft finally got it right. But to use WPF data-binding, you need to set up your domain model just so. Individual properties need to implement the PropertyChanged event, and collections need to raise the CollectionChanged event. That seems like a fairly harmless requirement, but developers who use Domain-Driven Design (DDD) hate it. You see, to a DDD developer, WPF pollutes the domain model and destroys Separation of Concerns. From a DDD purist’s point of view, WPF is just another bad Microsoft technology.

NHibernate really hates the collection constraint. While the preferred collection type for WPF is ObservableCollection<T>, NHibernate absolutely requires that domain collections be of type IList<T> (or IESI.ISet<T>), which provide no change notification whatsoever. If you use NHibernate as your ORM, the conventional wisdom has said that you are pretty much locked out of WPF, at least until now.

So, how do we make WPF and NHibernate play nice together? And, how do we make WPF palatable to DDD developers? DDD purists offer this approach: Wrap domain model objects that you want to expose in your view—wrap them in view model wrappers (VM wrappers), classes that provide the functionality that WPF requires. Now, that sounds straightforward enough. But if you have ever tried to actually do this, you know what a mind-numbing, stultifying, time-consuming chore this task can be. The rest of you, just think of dental work.

This article demonstrates a toolkit that gets everyone to play nice together, and makes the task of creating VM wrapper classes almost trivial. The heart of the toolkit is VM Wrapper Express 2.0, a utility that generates wrapper classes in the blink of an eye. The article also includes a demo app, VM Collection Demo, that shows how the wrapper classes work, and how to use them in your own applications.

VM Wrapper Express has been updated since the original version of this article. The changes from Version 1.0 to Version 2.0 are discussed in the body of the article. But let’s start with some background first—a look at the Separation of Concerns issues presented by the combination of NHibernate and WPF.

Version 2.1 Update

VM Wrapper Express has been updated to Version 2.1. While using the application, I discovered that the WPF DataGrid became uneditable when I used it with wrapper classes generated by VMWE. Version 2.1 fixes the problem; I discuss the problem and the fix below.

VM Wrapper Express has an installer project. If you simply want to install the program, you can find the installer in the SetupVmWrapperExpress\bin\Release folder.

Separation of Concerns

The principle of Separation of Concerns says that a class should do one thing and do it well. View classes should be concerned with the view, data access classes should be concerned with data access, and the domain model should be concerned with modelling the problem domain. The domain model shouldn't concern itself with either data access or display—to the extent we have to bend the domain model out of shape to meet the requirements of either our ORM or our display technology, we are polluting our domain model with extraneous concerns.

There seems to be a general consensus among DDD developers (except for the real purists, and they scare the rest of us) that NHibernate’s requirement that all collections be IList<T> or IESI.ISet<T> collections does no real violence to Separation of Concerns where the domain model is concerned. IList<T> is a lowest-common-denominator interface for .NET collections, as is ISet<T>. Even if an application does not use NHibernate, odds are that whatever collection type is used will implement IList<T>. So, we have no real concern here.

WPF requires individual objects to implement the PropertyChanged event, and it requires collection properties to implement the CollectionChanged event. In effect, those requirements mean that classes that interact with WPF must implement the INotifyPropertyChanged interface, and their collection properties must be of type ObservableCollection<T>. Arguably, those constraints are no more onerous than NHibernate’s constraint to IList<T>. Maybe they are, and maybe they aren't. But, we can all agree that a class that works with WPF absolutely will not work with NHibernate.

Does it Matter?

Even without the NHibernate problems, I would be concerned about the extent to which WPF bends a domain model out of shape. The entire idea behind object-oriented programming (and Separation of Concerns) is to minimize the coupling between the different portions of a program. If I keep my domain model (and my other business logic) separated from both WPF and NHibernate, then I can replace either of them down the road, should the need arise, without having to make major changes to the other two components. If Microsoft hits a home run with Version 2 of the Entity Framework, I should be able to replace NHibernate without having to tear apart either my domain model or my user interface. And, if another display technology supplants WPF down the road, I should be able to update the UI without tearing up the back end of my application.

The ability to make these kinds of changes convinces me that some additional work is well-worth the effort involved. It’s all a question of how much work is required to maintain a separation of concerns. The WPF-NHibernate Toolkit is designed to minimize the extra work involved in separating your user interface from the back end of your program.

Does It Need to Be This Complicated?

Paulo Quicoli brought up a great point when this article was first published. Paulo is the author of WPF + M-V-VM + NHibernate + NHibernate Validator = Fantastic Four! It’s a great article, one that I would recommend to anyone learning WPF. Anyway, Paulo asked, in effect, if you could accomplish the same result much more easily using the following approach:

  • Implement INotifyPropertyChanged on your individual domain objects
  • Make your NHibernate collections IList<T> collections
  • For WPF, inject those collections into ObservableCollection<T> collections using the constructor that takes an IList<T>
  • To persist back to the database, simply cast the ObservableCollection<T> as an IList<T>

As Paulo pointed out, this solution will work, as he demonstrates in his article.

Paulo is absolutely correct, and in a small-scale application, that approach will work very well. However, in a large-scale application, it will result in a performance hit. Here’s why: NHibernate takes a snapshot of the objects that you retrieve, and caches the snapshot in the ISession object. When you persist back to the database, NHibernate compares the current state of your objects to the snapshots in its cache. It only writes the objects that have actually changed.

To enable NHibernate to perform this trick, you must maintain object identity throughout your session. In other words, you have to pass the same objects back to NHibernate that it originally passed to you. When you inject your IList<T> into an ObservableCollection<T>, you are creating a new collection, which breaks object identity. So, when you cast the ObservableCollection<T> back to an IList<T>, you will have a faithful copy of your original collection, but you will not have the original. As a result, NHibernate will fall back to writing everything back to the database. So, even if you change only one object in a collection of one thousand, the entire collection gets written back to the database.

It is worth noting that if you do decide to implement INotifyPropertyChanged on your individual objects, it would eliminate the need to wrap those objects. As a result, you could probably simplify VmCollectionBase<VM, DM>, since it will have access to domain objects, instead of wrappers. I like to keep my domain models as clean as possible, so at this point, I am wrapping all of my individual domain objects. But it’s a close call—I can see the merits of the argument that implementing INotifyPropertyChanged does not pollute my domain model in any meaningful way.

Model-View-ViewModel

Most WPF gurus recommend using the Model-View-ViewModel (MVVM) pattern to organize WPF applications. The idea behind MVVM is that we create a view model class for each view in our application. The view model provides an abstract representation of the commands and data needed by the view, as well as the programming logic required to drive the display. The tremendous advantage to this pattern is that WPF can data-bind to both commands and data in a very simple, easy-to-implement way.

I won't spend any time on MVVM in this article. There are a number of good articles about MVVM on the web. And Jason Dolinger, of WPF developer Lab 49, did a very good screencast on the subject that can be found on the Lab 49 blog. But, there are a couple of points I would like to make about MVVM before we move on:

  • A view model does not wrap an entire domain model. Instead, it wraps selected classes in a domain model—those classes that will be exposed in a particular view.
  • A view model is not a single class. A view model is typically made up of a number of classes, including wrapper classes, IConverter classes, and utility classes. However, these classes are typically organized by a single view model class, which is set as the DataContext of a WPF Window (or control), and which acts as a Façade to the other classes.

In this article, when we refer to a view model (in lower case), we are referring to the groups of classes that make up the view model for a particular view. When we refer to the ViewModel, we are referring to the Façade class. Now, on to the toolkit.

Encapsulation of Domain Objects

One of the design goals in Version 2.0 of VM Wrapper Express is to improve the encapsulation of domain objects. Ideally, a wrapper object should hide the domain object from the view. In other words, the view should only see the wrapper objects in the view model, not the domain objects inside the wrappers. That approach prevents a developer from mistakenly accessing domain objects and breaking data binding in the UI. In the original version of VM Wrapper Express, wrapped objects exposed the domain object in a public property, DomainObject. As a result, domain objects were not hidden from the view by their wrappers.

The need for a public DomainObject property stemmed from the fact that the VmCollectionBase class needs access to wrappers' domain objects. New VM objects can be created in the view by data binding operations—for example, see the Add and Remove buttons in the VM Wrapper Demo application. These new objects are typically added to VM collections. In that case, the VmCollectionBase class responds to the change in the VM class and pushes the change out to the domain model. To do that, the VmCollectionBase class needs access to the domain object in the new or deleted VM, to push the change out to the domain model.

Version 2.0 improves on the situation somewhat by making the DomainObject property internal. So long as the view model is compiled in a separate assembly from the view, the VM object will hide the domain object from the view, while still making it accessible to the VmCollectionBase class. The VM Wrapper Demo solution utilizes this approach.

However, if the view and the view model are contained in the same assembly, the DomainObject property will be visible to the view. For this reason, while Version 2.0 improves on the original version of VM Wrapper Express, I am not entirely happy with the result. If any reader can recommend a better approach to encapsulating the domain object, I would be very open to the suggestion.

Note that in the VM Wrapper Demo application, we break the rule about hiding the domain object. In fact, the view model exposes the entire domain model as a property, where it is readily accessible by the view. It does this so that the view can inspect domain objects in order to demonstrate that changes have been pushed out to the domain model. Note that I do not recommend doing this as a general practice. As we discussed above, the view model should provide the view's sole access to the properties of the domain model.

The Toolkit

There are two parts to the toolkit:

  • VM Wrapper Express: A utility that generates VM wrappers for domain objects and collections.
  • VM Wrapper Demo: A simple demo program that shows how to use the classes generated by VM Wrapper Express.

VM Wrapper Express does not wrap all objects that are contained in a domain model. Instead, it wraps only those objects that you want to expose in a view model. The wrappers are implementations of the Gang of Four Adapter pattern.

The Wrapper Classes

VM wrappers fall into two categories:

  • Object wrappers: These classes wrap individual domain classes, like the Customer and Order classes in the demo app. Object wrappers are unique to the domain classes they wrap.
  • Collection wrappers: These classes wrap individual collection classes, like the Customers and Orders collection classes. These collection wrappers are skeleton classes, and they derive all their functionality from the VmCollectionBase<VM, DM> class. I discuss the reasons for this approach below.

Prior to Version 2.1, VM Wrapper Express did not generate individual wrapper classes for collection classes. Instead, it used a generic VmCollection<VM, DM> class. To wrap a collection, the developer simply declared a property to be of type VmCollection<VM, DM> (VM and DM are explained below). This worked well in most scenarios. However, for reasons that are not entirely clear, this approach caused the WPF DataGrid to become uneditable when it was bound to a property of this type. For some reason, the WPF DataGrid sets the IEditableCollectionView.CanAddNew property to false whenever it is bound to a generic class with more than one generic parameter.

The solution turns out to be rather simple. We simply declare a skeletal collection wrapper for each collection class. The wrapper derives from the VmCollectionBase<VM, DM> class. The collection wrapper does not need to implement any separate functionality, since its sole purpose is to work around the WPF DataGrid bug. So, as of Version 2.1, we have a VmCollectionBase<VM, DM> class, and individual collection wrappers derived from that base class. The new base class behaves identically to the old generic class.

The VmCollectionBase class has two generic type variables (which behave identically to their counterparts in the old generic class):

  • VM: This generic type variable represents the type of object wrapper that is contained in the collection.
  • DM: This generic type variable represents the type of domain object that is wrapped by the VM class.

We put quotes around ‘wraps’ when discussing collection wrappers because VmCollectionBase<VM, DM> doesn't really wrap an IList<T> collection. Rather it duplicates it, to hold a collection of object wrappers. But, the effect is the same as if it had wrapped the collection.

The object and collection wrappers are designed so that any changes made to the wrapper object’s properties flow back to the corresponding properties in the wrapped domain object. There are two types of changes involved:

  • Object property changes: Since object wrapper properties are wired directly to their counterparts in the wrapped domain object, any change in the wrapper object is immediately passed to the domain object.
  • Collection changes: VmCollectionBase<VM, DM> handles its own CollectionChanged event when objects are added to or removed from the collection. In these cases, the same action is pushed back to the wrapped domain collection—a new domain object is added (with a corresponding object wrapper), or the domain object that corresponds to a removed object wrapper is itself removed from the domain collection.

These methods keep the view model and domain model collections synchronized with each other.

Note that VM Wrapper Express creates both an individual object wrapper and a collection wrapper for each domain object selected in the main window. Generated wrappers are placed in three subfolders under the folder selected in the main window: BaseClasses, CollectionWrappers, and ObjectWrappers. Once you have used VM Wrapper Express to generate wrapper classes, you can decide which wrappers you need to use in your view model. In my applications, I normally generate classes to a Wrappers folder in the view model project, then move the base classes from that folder to wherever the other base classes for the project are stored. This is the approach used in the VmWrapperDemo app.

Direction of Change in the Wrapper Classes

Note that the direction of flow for changes remains one-way in Version 2.0; that is, changes to a wrapped object or collection flow to the wrapped domain object or collection, but not vice versa. As a result, after a domain object or collection is wrapped, changes to the domain object or collection do not flow to their wrappers. This approach is based on the idea that once an object is wrapped, it should only be accessed via its wrapper. The demo app’s Add Customer command reflects this approach. A new object wrapper (which contains a new domain object) is added to the view model collection; the wrapper collection then pushes the new wrapped object out to the wrapped collection.

Bug Fixes in Previous Versions

I discovered a bug in Version 1.0 of VM Wrapper Express that arose whenever a domain class had a property that was typed to another domain class. Let’s say you have a domain class whose properties are all simple .NET types; strings, ints, and the like. When the UI calls a wrapped property, it wants the string or its value that the property wraps. But what if a domain class has a property that is another domain type? For example, a Customer class may have an Address property that is typed to a domain class called Address. This latter class has properties for StreetNumber, StreetName, City, State, and Zip (assuming it’s a USA address). In that case, what the UI wants is the wrapped address object, from which it can then get the information it needs.

The object wrappers generated by the original version of VM Wrapper Express didn't make this distinction—if a domain class property was typed to another domain class, it simply tried to return the second domain object. Version 2.x of VM Wrapper Express wraps the second domain object in a VM wrapper before it passes it to the caller, which is the expected behavior.

CodeProject member Skendrot posted a message in response to the original article pointing out that the original solution did not account for lazy loading. He suggested a fix that I liked so well that I incorporated it without change in Version 2.0. You can find his original message at the end of this article. Thanks, Skendrot!

The Demo Application

The demo application is changed slightly in Version 2.1--it now uses individual collection wrappers, rather than the generic collection wrapper from Version 2.0. Its behavior is identical to Version 2.0. The demo shows how the wrapper classes are used in a simple application:

VmWrapperDemo.png

The demo app is built on the Model-View-ViewModel pattern; code-behind is kept to a minimum, and most control logic is contained in the app’s view model classes, which are found in the view model folder.

Each of the buttons in the main window demonstrates a different type of operation on the domain model. When you click a button, the demo app applies the operation to the wrapper class (not the wrapped domain class). The list boxes will update immediately, which shows that the operation has been propagated from the wrapper class to the view. The app then shows a message box which shows the results of the operation as read from the appropriate wrapper class property, and separately from the corresponding domain class property. The results should be the same from both sources, showing that the operation has been propagated from the wrapper class to the wrapped domain class.

The domain model is intentionally simplistic. The demo model offers the barest minimum of a Customers-Orders model, just enough to show how multi-level domain object wrapping works. Domain objects can be found in the Domain envelope. The main window for the application can be found in the view folder.

The view model is made up of a number of different classes. MainWindowViewModel (the Façade class) acts as a container for many of these classes; it is bound to the main window’s DataContext property on startup (in App.xaml.cs). The Commands folder contains the ICommand objects for the app’s commands. These objects are exposed as ICommand properties in the view model class. The Converters folder contains several IValueConverter classes that are used in data-binding operations between the view and the view model. The BaseClasses folder holds the base classes used by the view model and its wrappers:

  • ViewModelBase serves as a base class for view model classes. It provides an implementation of the INotifyPropertyChanged interface used in WPF data binding.
  • VmWrapperBase serves as a base class for object wrappers. It is derived from ViewModelBase and provides the INotifyPropertyChanged interface to wrapper objects. In addition, it provides the internal DomainObject property used by the VmCollectionBase class to push view model collection changes out to the domain model.
  • VMCollectionBase serves as a base class for collection wrappers.

Finally, the Wrappers folder contains object wrappers for the domain objects exposed in the view model. These wrappers are generated by the VM Wrapper Express utility.

The demo app is initialised in the App.xaml.cs class, in an override to the OnStartup() event handler. The demo app mocks NHibernate, rather than implement it to any degree. It simply creates a couple of Customer objects, each of which has a couple of Order objects, and then wraps these collections in IList<T> collections, to emulate what we would get from NHibernate. If you need to know how to use NHibernate to get these objects from a database, I would suggest my article, NHibernate Made Simple, also on CodeProject.

When the demo app launches, it presents a rather ordinary master-detail view, made up of two list boxes. The top list box lists customers, and the bottom list box lists orders for the selected customer. A series of buttons appear below the list boxes; each button demonstrates a different task involving wrapped objects.

The buttons are bound to the demo app’s ICommand objects, which (as we noted above) are exposed as command properties on the view model. The command logic is all rather straightforward, so I won't belabor it here.

Wrapping Domain Objects in the Demo App

The main object wrapping is done in App.xaml.cs. The OnStartup() override creates a couple of Customer objects and populates them with Order objects; then, it passes the IList<Customer> it has created to the view model:

// Create view model
MainWindowview model mainWindowview model = new MainWindowview model(customers);

The view model constructor initializes its Customers property as a new CustomersVM collection class, and passes the IList<Customer> to the collection’s constructor:

// Initialize collections
this.Customers = new CustomersVM(customers);

At that point, VmCollectionBase gets down to work:

// Populate this collection with VM objects
VM wrapperObject = default(VM);
foreach (DM domainObject in domainCollection)
{
    wrapperObject = new VM();
    wrapperObject.DomainObject = domainObject;
    this.Add(wrapperObject);
}

The code traverses the IList<Customer> and creates an object wrapper for each Customer object, injecting the domain object into the wrapper’s constructor, and adds these wrapper objects to its own internal collection. Pretty simple stuff, really. The process continues in a recursive chain that ensures that the entire object graph is wrapped to its deepest level.

Running the Demo

The demo is more-or-less self-explanatory. The master-detail data binding is done in XAML, using the ItemsSource properties of the two list boxes. The top list box is bound to the view model’s Customers property, like this:

<ListBox x:Name="listBoxCustomers" ItemsSource="{Binding Path=Customers}"  >

Then, the Orders list box is bound to the current Customer.Orders property, like this:

<ListBox x:Name="listBoxOrders" ItemsSource="{Binding Path=Customers/Orders}"  >

Note that the IsSynchronizedWithCurrentItem property is set to "True" for both list boxes. This ensures that both list boxes are set to the same Customer object.

You might notice that the UI has buttons to create new objects. These buttons invoke an operation that reverses the normal creation of a wrapper object. Normally, the domain object comes first, and it is injected into the wrapper object’s constructor. But when wrapper object creation is invoked from the UI, there is no pre-existing domain object. We need to create a new domain object to wrap in the VM wrapper. The UI does this by calling a second, parameterless constructor on the Wrapper object. This constructor instantiates a new domain object of the appropriate types and injects the new domain object into its own primary constructor.

Maintaining Flexibility

You will notice that we bind the SelectedIndex property of both list boxes to view model properties. These properties are used by several of the ICommands, to get the currently selected objects (see the Add Order and Remove Order ICommands). At first glance, this may seem a needless complication—why not simply have the view model read the ListBox property directly?

In a Model-View-ViewModel design, the view model should have no direct dependencies on the view. In fact, in production apps, I put all my view classes in one project, and all my view model classes in a separate view model project. The .NET compiler will not allow circular references, and my view project obviously has a reference to the view model project. As a result, the .NET compiler will not let me create a reference to the view in my view model, which means I can have no direct dependencies running from the view model back to the view. This approach goes a long way towards keeping my view models untangled from the views that are bound to them.

Is the extra work worth the effort? Let’s say I could call listBoxCustomer.SelectedIndex in the view model. Now, suppose a designer came along after I was done, and wanted to replace my rather drab looking list box with something more attractive. Unfortunately, they wouldn't be able to do so, since my view model is hard-coded to a list box. For the designer to be able to make that change, I would have to reopen my code and tie it to whatever the new control might be.

If I remove this dependency on a list box control, I increase the flexibility of my design. So, instead of binding my view model to a list box, I let the view bind to a property in the view model that provides the index of the object I want. And, I separate my views and view models into separate projects. That way, a designer can replace the list box with anything they want, so long as they provide the view model with the index in the Customers collection of the currently selected customer. That means I won't have to reopen my code, no matter what the designer wants to do.

The VM Wrapper Express Utility

The VM Wrapper Express utility generates custom object wrappers for domain model classes. Here is the main window, showing the domain classes for the VmWrapperDemo project:

VmWrapperExpress.png

Here are the steps to create view model classes with VM Wrapper Express:

  1. Load an assembly (an EXE or a DLL file) by clicking the Load Assembly button on the application toolbar, then selecting the assembly to load from the Open File dialog that appears. You will see a display that looks like the screenshot above.
  2. Select the classes that you want to wrap by clicking their checkboxes.
  3. Enter the namespace that Express should use when it creates your wrapper classes. At this point, the Generate Wrappers button should become enabled.
  4. Click the Generate Wrappers button, and select a destination for your wrapper class files from the folder browser that appears. When you click OK, the files will be generated.

You will probably find yourself re-generating wrappers a number of times during the course of development. You can save the configuration for a particular assembly by clicking the Save Settings button and saving the current settings in the Save File dialog that appears. The next time you need to generate wrappers for your project, you can reopen your previous session by clicking Open Settings, instead of Load Assembly. Express will load the assembly, select the previously-selected classes, and enter the view model namespace for you. All you have to do is click the Generate Classes button.

Using the Wrapper Classes

The demo app shows how to use the wrapper classes generated by VM Wrapper Express. First, add the wrapper classes you need to your development project-- I generally put them in a 'Wrappers' folder outside the project and import the wrappers I need into the project. In the demo app, the wrapper classes imported into the project are included in the View Model folder, distributed in three subfolders; BaseClasses, ObjectWrappers, and CollectionWrappers.

VM Wrapper Express generates all wrapper classes and base classes. So, all you have to do is import the classes you need (which should include all base classes) into your project. Once that is done, you can use wrapper classes just like you would use domain classes. The key difference is that the wrapped classes now implement the PropertyChanged and CollectionChanged events, so WPF will data bind with them nicely.

As we noted above, the wrapped domain objects, and the domain collections that contain them, retain their identities and characteristics. In other words, a wrapped domain class can be referenced directly, even when the class is wrapped inside a view model wrapper class. Simply retain a reference to your domain class. That way, when the time comes to persist the domain objects, they can be saved in the normal manner.

Note that persisting objects does not break the link between a domain object and its wrapper—there is no need to extract the wrapped domain object in any way. So, if you need to continue using the wrapper after saving the wrapped object, you may do so without having to take any additional steps.

In fact, the demo app shows most aspects of working with wrapped classes. Once you understand how it works, you should have no trouble integrating wrapped domain objects into your own development process.

Other Changes

The original version of VM Wrapper Express used property injection to inject a domain object into a newly-created VM wrapper. Normally, one would use constructor injection for this task, but .NET does not allow the use of parameterized constructors when using the new keyword to create a new object. Version 2.x of the VmCollectionBase class uses System.Reflection.Activator.CreateInstance(), which allows parameterized constructors, to create new VM objects. So, all wrapper classes now provide two constructors:

  • A parameterized constructor that takes the domain object; and
  • A parameterless constructor that creates a new domain object.

The first constructor is used when initialising a view model; the second constructor is used when a new VM object is created as the result of an operation in the view.

Conclusion

We have discussed the notion of wrapping domain classes primarily as a way of adapting NHibernate-friendly classes to make them WPF-friendly. However, there is an argument to be made that wrapping domain objects is a good idea whether one uses NHibernate or not. That’s because the wrappers free the domain model from any display or data-binding concerns. That promotes Separation of Concerns, and that’s always a Good Thing. If Microsoft changes its display or data-binding technologies in the future (and at some point, they certainly will), it will be much easier to rewrite wrapper classes than an entire domain model.

Put another way, VM wrapper classes enable the use of “POCO” objects (Plain Old CLR Objects) in a domain model. Domain-Driven-Design proponents will tell you that’s what keeps domain models flexible and focused on their sole job of modelling a problem domain. And ultimately, that makes applications easier and less expensive to maintain over time.

Please post comments regarding any bugs that you find in either the demo app or VM Wrapper Express, or with any suggestions for improving either program. I will post updates to the article to incorporate significant suggestions or bug fixes. I will be happy to answer questions regarding the article and the included applications, but I am unable to help with other programming problems. I hope you find the article and VM Wrapper Express as useful as I have.

History

  • 05/01/2009: Original version posted
  • 05/05/2009: Added ‘Does It Need to Be This Complicated?’
  • 08/17/2009: Revised for Version 2.0 of VM Wrapper Express
  • 10/26/2009: Updated code for VM Wrapper Express
  • 10/31/2009: Fixed WPF DataGrid bug in collection wrapper, added application icon
  • 01/15/2010: Fixed bug in VM Wrapper Express Setup project

License

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

Share

About the Author

David Veeneman
Software Developer (Senior) Foresight Systems
United States United States
David Veeneman is a financial planner and software developer. He is the author of "The Fortune in Your Future" (McGraw-Hill 1998). His company, Foresight Systems, develops planning and financial software.

Comments and Discussions

 
GeneralCode Update PinmemberDavid Veeneman26-Oct-09 14:56 
GeneralBugs Pinmemberlolic231-Aug-09 23:30 
GeneralRe: Bugs PinmemberDavid Veeneman1-Sep-09 9:09 
Generaleloquent and challenging ! PinmemberBillWoodruff24-Aug-09 8:51 
GeneralRe: eloquent and challenging ! PinmemberDavid Veeneman24-Aug-09 16:48 
General2nd WPF Disciples says this is a-ok PinmvpSacha Barber18-Aug-09 20:52 
GeneralAs one of the proponents of DDD, .... Pinmemberi.j.russell18-Aug-09 9:22 
GeneralRe: As one of the proponents of DDD, .... PinmemberDavid Veeneman31-Aug-09 15:38 
GeneralAs one of the proponents of MVVM, I like this article PinmvpPete O'Hanlon17-Aug-09 10:14 
GeneralRe: As one of the proponents of MVVM, I like this article PinmemberDavid Veeneman17-Aug-09 12:24 
GeneralRookie question - using a database Pinmemberjastewart13-Aug-09 2:49 
GeneralRe: Rookie question - using a database PinmemberDavid Veeneman13-Aug-09 11:23 
GeneralRe: Rookie question - using a database Pinmemberjastewart14-Aug-09 8:15 
GeneralRe: Rookie question - using a database PinmemberDavid Veeneman14-Aug-09 8:21 
GeneralRe: Rookie question - using a database Pinmemberjastewart14-Aug-09 8:55 
GeneralRe: Rookie question - using a database PinmemberDavid Veeneman14-Aug-09 9:00 
GeneralRev. 2.0 coming PinmemberDavid Veeneman11-Aug-09 10:40 
GeneralLazy Load Pinmemberskendrot13-May-09 4:07 
GeneralRe: Lazy Load PinmemberDavid Veeneman13-May-09 5:12 
GeneralBindingList Pinmemberquicoli4-May-09 1:07 
GeneralRe: BindingList PinmemberDavid Veeneman4-May-09 2:43 
GeneralRe: BindingList Pinmemberquicoli4-May-09 3:08 
GeneralRe: BindingList PinmemberDavid Veeneman4-May-09 4:58 
GeneralRe: BindingList Pinmemberquicoli4-May-09 6:11 
GeneralRe: BindingList PinmemberDavid Veeneman4-May-09 7:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140821.2 | Last Updated 17 Jan 2010
Article Copyright 2009 by David Veeneman
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid