Home » Programming » .NET Programming » Silverlight 4, MEF and MVVM: EventAggregator, ImportingConstructor and Unit Tests

    I had recently the possibility to use MEF and Silverlight in a sample project together with Prism, this is for sure a great combination of frameworks for bulding applications using maintainable and extensible code. I don’t think that using MEF excludes the usage of Prism and vice versa,  the choice should be pondered and analyzed accordingly to the problem to solve.

    Starting from the previous experiments, I decided to refactor and cleanup the MVVM approach in order to:

    • obtain simpler code;
    • inserting an EventAggregator managed by MEF to exchange messages;
    • maintaining the Visual Studio designer/Blend support;
    • trying a simple unit test using the framework available in the Silverlight Toolkit.
    1. Using the EventAggregator

    The first step is inserting in the project the Prism EventAggregator downloading the “Microsoft.Practices.Composite.dll” and “Microsoft.Practices.Composite.Presentation.dll” libraries from the Prism site on Codeplex.

    It’s now possible to make available in the application an instance of it using this syntax:

    public class EventAggregatorProvider
    {
       [Export(typeof(IEventAggregator))]
       public IEventAggregator eventAggregator { get { return new EventAggregator(); } }
    }
    

    In this way we are able to import it in the ViewModel class using an [ImportingConstructor] attribute:

    [ImportingConstructor]
    public MainPageViewModel(IEventAggregator eventAggregator, IDataItemsService dataItemsService)
    {
       _eventAggregator = eventAggregator;
       _dataItemsService = dataItemsService;
    }
    

    When an [ImportingConstructor] is found, MEF looks for an [Export] for each parameter available in the constructor, in this case we must have exported an “IEventAggregator” and an “IDataItemsService”.

    We are now able to access the instance of the EventAggregator and Publish/Subscribe to events using a syntax like:

    //Call the Service
    _dataItemsService.GetDataItems();
    
    //Subscribe to the "DataItemsReceivedEvent"
    
    _eventAggregator. GetEvent<DataItemsReceivedEvent>(). Subscribe(
        dataItemsReceived =>
        {
            this.dataItems = dataItemsReceived;
        },
        true
    );
    

    In this case we are receiving the result of the async calls via the EventAggregator and a DataItemsReceivedEvent:

    public class DataItemsReceivedEvent : CompositePresentationEvent<DataItems> {  }
    

    DataItemsService code publishing the Event:

    //Initialize the collection
    DataItemWcfService.DataItemServiceClient svc = new DataItemWcfService.DataItemServiceClient();
    svc.GetDataItemsCompleted += (s1, e1) =>
    {
        if (e1.Result != null)
        {
            var dataItems = new DataItems();
            e1.Result.ToList().ForEach(d =>
            {
                dataItems.Add(new DataItem() { Description = d.Description });
            });
    
            //Publish the DataItems
            _eventAggregator. GetEvent<DataItemsReceivedEvent>(). Publish(dataItems);
    
            isLoading = false;
        }
    };
    svc.GetDataItemsAsync();
    isLoading = true;
    }
    

    2. Maintaining the Visual Studio designer/Blend support

    In the previous experiments I enabled design-time data by inserting a new ViewModel class which can create some confusion, so I decided to skip this step and using a unique ViewModel following this approach:

    • the ViewModel parameterless constuctor contains the initialization for data to be used during design time and tests;
    • the other constructor marked with the MEF [ImportingConstructor] attribute enables initialization of services and event aggregator.
    [ImportingConstructor]
    public MainPageViewModel(IEventAggregator eventAggregator, IDataItemsService dataItemsService)
    {
        _eventAggregator = eventAggregator;
        _dataItemsService = dataItemsService;
    }
    

    3 – Unit Test

    To verify the approach described, I’ve inserted a new “Silverlight Unit Test project” to the solution (note that the “Silverlight Toolkit” must be installed to use this feature) and then a simple Test method containing the following code:

    [TestClass]
    public class Tests
    {
        [TestMethod]
        [Description("Test the creation of a ViewModel and the initialization of Design/Test Data")]
        public void TestViewModelCreation()
        {
            var vm = new MainPageViewModel();
            Assert.IsNotNull(vm);
            Assert.AreEqual(vm.dataItems.Count, 2);
        }
    }
    

    Since MEF is only used to compose run-time Parts, I’m not using it in the Unit Tests.

    So we have now a new piece of code, which I’ve called a “MEFModule” organized with a MVVM approach and ready for design-time support, unit tests and extensibility: ready to be inserted in a Navigation applicationdynamically loaded and enabled for design time using Blend Sample Data, stay tuned.

    The source code is available for download here.

    Happy Silverlighting!

    7 thoughts on “Silverlight 4, MEF and MVVM: EventAggregator, ImportingConstructor and Unit Tests

    1. Fallon Massey says:

      I’m curious as to why you use PRISM for messaging, instead of something like MVVM Light, which has a much smaller footpring.

      Your app is almost 500MB to download before anything happens.

      Actually MEF is getting to be a big download, but since you can dynamically load, it may offset the size.

      Were there some technical reasons? I think that PRISM events are threaded, and MVVM Light behaves like a method call, but I’m not 100% positive on that.

    2. Davide says:

      @Fallon: no particular reason, in this sample I’m using EventAggregator but you can use MVVM Light messaging as well :)

    3. Dave says:

      You don’t even have to go that far with the EventAggregator. A class this simple will do:

      [Export(typeof(IEventAggregator))]
      public class ContractLoaderEventAggregator : EventAggregator {
      }

      This works like a charm. Drop me an email if you have questions.

    4. Davide says:

      Hi Dave,
      Great suggestion, thanks!

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>