Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.

  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint
Share this Page URL
Help

6. MVVM > Connecting a View to a ViewModel using MEF

Connecting a View to a ViewModel using MEF

Connecting a View to a ViewModel using MEF Applies to Silverlight 4 and 5 In the previous recipe, we used the ViewModelLocator to connect our Views to our ViewModels. Another approach you can take is to use the Managed Extensibility Framework (MEF) to do this for you. One of the advantages of this approach is that besides relaying the responsibility of providing the ViewModels to MEF, you can now use multiple ViewModel instances of the same type without having to create a ViewModelLocator property for each, for example: you can use this approach if you don't know in advance how many instances you'll need (amongst some other advantages, which will be described in this recipe). In this recipe, you'll learn how to use MEF for tying your Views to your ViewModels. Getting ready We're starting with the solution we completed in the previous recipe, Connecting a View to a ViewModel using a ViewModelLocator. Or alternatively, you can start with the provided starter solution, which can be found in Chapter 6\Connecting_View_ViewModel_ MEF_Starter. The completed solution can be found in Chapter 6\Connecting_View_ViewModel_MEF_Completed. How to do it... We're going to adjust the solution from the previous recipe, Connecting a View to a ViewModel using a ViewModelLocator, or the starter solution, so it uses MEF to tie the View and ViewModel together. To achieve this, we should complete the following steps: Right-click on MVVM.Client, select Add Reference, and add references to System.ComponentModel.Composition and System.ComponentModel.Composition.Initialization.Remove ViewModelLocator.cs from MVVM.Client.Open App.xaml, and remove the ViewModelLocator resource: <vm:ViewModelLocator x:Key="Locator" /> Add a new folder to MVVM.Client, Contracts, by right-clicking MVVM.Client and selecting Add | New Folder. In this folder, add a new interface, IPersonViewModel, as such: public interface IPersonViewModel { } Open PersonViewModel.cs, and add the following using statements: using System.ComponentModel.Composition; using MVVM.Client.Contracts; Add the following attributes to the class signature: [Export(typeof(IPersonViewModel))] [PartCreationPolicy(CreationPolicy.Shared)] public class PersonViewModel : ViewModelBase Open PeopleView.xaml and remove the DataContext binding statement: DataContext="{Binding Source={StaticResource Locator}, Path=PersonVM}" Open PeopleView.xaml.cs, and add the following using statements: using GalaSoft.MvvmLight; using System.ComponentModel.Composition; using MVVM.Client.Contracts; Change the constructor and add a ViewModel property as such (IsInDesignModeStatic isn't necessary, but it's added to ensure the design view still works): public PeopleView() { InitializeComponent(); if (!(ViewModelBase.IsInDesignModeStatic)) { // load VM through MEF CompositionInitializer.SatisfyImports(this); } } [Import(typeof(IPersonViewModel))] public ViewModelBase ViewModel { set { this.DataContext = value; } get { return this.DataContext as ViewModelBase; } } You can now build and run your application. How it works... In our PeopleView.xaml.cs, we've added a property ViewModel, which is decorated with an import statement as such: [Import(typeof(IPersonViewModel))] public ViewModelBase ViewModel With this import statement, we're stating that the ViewModel property should be of type IPersonViewModel. In the constructor of the PeopleView, we've added a call to CompositionInitializer.SatisfyImports(this). This means that whenever the View is instantiated, all the imports in this View should be satisfied. As we've added an import statement on the ViewModel property, that import will be satisfied. To satisfy this, MEF will go and look for anything that has been exported as an IPersonViewModel (which is used as a marker interface—regular strings are also accepted, but are prone to type errors). If it finds one, it will instantiate (the composition), and set it as the value of the ViewModel property in PeopleView.xaml.cs. The setter of that ViewModel property sets the View's DataContext to that imported value, for example: to an instance of anything that is exported as IPersonViewModel. In this case, we've exported the PersonViewModel as something of type IPersonViewModel. This means that MEF will set the ViewModel property on our View to an instance of PersonViewModel. That is thus the DataContext of our View, so the View and ViewModel are connected now, and everything works as it should. There's more... There's a lot more to MEF than this simple example, but let's start with an explanation of what MEF does. MEF, or the Managed Extensibility Framework, was designed to simplify the design of extensible applications and components. A lot of applications have requirements that change frequently, and it might become difficult to extend the application with new functionality after some amount of time; MEF tries to solve this problem by making it easy to plug new functionality into your application. The first keyword is Composition: you start by telling MEF where it can find the parts of the application it needs to provide by creating a catalog (this might be, for example, a catalog of all types in the currently executing assembly). From this catalog, you then create a CompositionContainer. This container will do the work for you from now on.The second keyword is Export: by exporting a component with the Export attribute, you tell MEF you want to export this component (type, property), so it can be composed via the container.The third keyword is Import (or ImportMany), which tells MEF what type of components should be imported via the container in a specific part of your application. Note These three simple concepts are the heart and brains of MEF. While this isn't a book on MEF, this should give you a basic understanding of what MEF is and what it does. A lot more information can be found at http://mef.codeplex.com/. With that in mind, we can look at some of the specifics of this recipe: what about the PartCreationPolicy attribute we've used on PersonViewModel? We've exported our ViewModel with a CreationPolicy of Shared—this means the same ViewModel instance will be reused whenever it is asked for by an Import statement. However, if you want to ensure new instances are used every time (typically the case when you want to reuse the same View/ViewModel combination for an unknown number of times), you can make it NonShared. Have a look at the following code example: [Export(typeof(IPersonViewModel))] [PartCreationPolicy(CreationPolicy.NonShared)] public class PersonViewModel : ViewModelBase The preceding code will ensure a new instance is created each time an Import on this type is called. But what about tying different Views to the same ViewModel type? Well, the same approach can be used: identify your ViewModel as Exported in a Shared way, and the same ViewModel instance (holding the state) will be reused as DataContext for whichever View imports it. This makes it very easy to reuse the same underlying data, but presenting it in a different way. And if you need different instances of the same ViewModel type for different Views, simply export the ViewModel as NonShared. Note that, in essence, we're using MEF for dependency injection in this approach. Not everyone (as with almost all patterns, frameworks, and building blocks) agrees that this is a correct approach, or something that should be done. If you don't want to use MEF, you can easily use an IoC container, such as Castle (http://www.castleproject.org/) or Ninject (http://ninject.org/), to get this result; that will, however, require external references to those containers, while MEF is part of the core .NET Silverlight CLR. MEF is not an Inversion of Control container, but it of course uses IoC to do its business. And it even allows you to do more than your typical IoC container: an IoC container typically works on known dependencies. MEF was designed to manage your unknown dependencies, hence the plugability promise. However, that doesn't mean you can't manage your known dependencies with it as well—at least up to a certain point. Some applications use MEF as a replacement for their standard IoC containers like Castle or Ninject, other applications use both: an IoC container for known dependencies, MEF for unknown ones. The choice is yours, but for more demanding, enterprise-grade applications, a mix of an IoC container and MEF is often the way to go. See also For more information on MVVM, have a look at the other recipes in this chapter.

  

You are currently reading a PREVIEW of this book.

                                                                                                                    

Get instant access to over $1 million worth of books and videos.

  

Start a Free 10-Day Trial


  
  • Safari Books Online
  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint