Mar
21
2011
Back on December 2, 2010 John Papa gifted the community with an excellent example of proper Silverlight architecture and I have been recommending people watch the video, download John’s code, and follow the pattern to create their own applications.
Over the last couple of weeks I have started a new project at work and this time I have decided to follow the example I have given to others. This experience is showing some places where my own preferences diverge from John’s so I have decided to share my changes with the community. I am taking the experiences in my own project and porting them into John’s project. I am not going to dump all of my changes in at once, I am going to be making gradual changes across at least three blog posts. In this first post I will be integrating Marlon Grech’s MEFedMVVM library into John’s code. Over the new two blog posts I will be changing the DataServices to use ICollectionView instead of EntityList and in the third post I will be changing the design time DataServices to use the actual RIA Servics entities instead of separate design time entities. Kyle McClellan on the RIA Services team at Microsoft has come up with something better then what I was working on for parts 2 and 3. Check it out at http://blogs.msdn.com/b/kylemc/archive/2011/04/29/mvvm-pattern-for-ria-services.aspx. I will be posting up a MEFed up version of Kyle's project.
MEFing up the code
Out with the old
I am going to be gutting John’s provider and locator code to replace them with MEFedMVVM replacements. This means that I first deleted the following classes:
- Assets\ObjectResourceDictionary
- DesignServices\DesignServiceConductor
- Services\ServiceProvider
- Services\ServiceProviderBase
- ViewModels\ViewModelLocator
Then I removed the following line from the App.xaml
<ResourceDictionary Source="Assets/ObjectResourceDictionary.xaml"/>
MEFing up the views
Now I was ready to put MEFedMVVM into place. First I coped MEFedMVVM.SL.dll into the Lib directory of the project and added a reference. Then I needed to add MEF itself which is done by referencing System.ComponentModel.Composition
Next, BookView.xaml, CheckoutView.xaml, and EditBookWindow.xaml need the meffed namespace registered:
xmlns:meffed="http:\\www.codeplex.com\MEFedMVVM"
Then in BookView.xaml and EditBookWindow.xaml John’s original locator code was replaced with:
meffed:ViewModelLocator.SharedViewModel="Book"
In CheckoutView.xaml the locator code was replaced with:
meffed:ViewModelLocator.NonSharedViewModel="Checkout"
The use of SharedViewModel and NonSharedViewModel mirrors the original design that John used. BookView.xaml and EditBookWindow.xaml will share the same instance of the ViewModel while CheckOutView.xaml will get a new instance of its ViewModel every time it loads.
MEFing up the ViewModels
I registered the BookViewModel with MEF using the MEFedMVVM ExportViewModel attribute
[ExportViewModel("Book")]
public class BookViewModel : ViewModel
then I decorated the constructor:
[ImportingConstructor]
public BookViewModel(IPageConductor pageConductor,IBookDataService bookDataService)
CheckoutViewModel was edited the same way:
[ExportViewModel("Checkout")]
public class BookViewModel : ViewModel
public CheckoutViewModel(IPageConductor pageConductor,IBookDataService bookDataService)
MEFing up the DataServices and PageConductors
Last step was registering the DataServices and PageConductors. These were registered with MEF using MEFedMVVM’s RegisterService attribute which allows us to set a ServiceType of Runtime, DesignTime, or Both. By registering the DesignBookDataService and the DesignPageConductor as having a ServiceType of DesignTime we will get the same design time data support that John had in the original version.
[ExportService(ServiceType.DesignTime, typeof(IBookDataService))]
public class DesignBookDataService : IBookDataService
[ExportService(ServiceType.DesignTime, typeof(IPageConductor))]
public class DesignPageConductor : IPageConductor
[ExportService(ServiceType.Runtime, typeof(IBookDataService))]
public class BookDataService : IBookDataService
[ExportService(ServiceType.Runtime, typeof(IPageConductor))]
public class PageConductor : IPageConductor
Conclusion
I think the MEFedMVVM way of doing things is both simpler and more powerful than John’s original method. It greatly reduces the amount of classes needed and makes it much easier to add new Views, ViewModels, and DataServices to your solution. Here is the ZIP file containing the modified solution:
MEFedUpRIAServicesMVVM.zip (6.56 mb)