Classes deriving from ObservableObject or ViewModelBase can use the following methods:
RaisePropertyChanged("MyProperty"); RaisePropertyChanged(() => MyProperty); // very small performance impact Set("MyProperty", ref myProperty, value); // the "Set" methods return a bool value indicating if the property // value has changed Set(() => MyProperty, ref myProperty, value);
Overloads suitable to use with the Messenger:
RaisePropertyChanged("MyProperty", oldValue, value, true); RaisePropertyChanged(() => MyProperty, oldValue, value, true); Set("MyProperty", ref myProperty, value, true); Set(() => MyProperty, ref myProperty, value, true);
The parameters in the above methods are:
MVVM Light has a PropertyChanging event. It provides access to the old value:
RaisePropertyChanging("MyProperty"); RaisePropertyChanging(() => MyProperty);
ObservableObject is lighter than ViewModelBase, for example it does not have the design mode detection.
Example: Register a class to SimpleIoC:
// Class registration. SimpleIoc.Default.Register<MainViewModel>(); // Registration with an interface. SimpleIoc.Default.Register<IDataService, DataService>(); // Conditional registration. if (condition) SimpleIoc.Default.Register<IDataService, DataService>(); else SimpleIoc.Default.Register<IDataService, TestDataService>();
Example: Register a class to SimpleIoC using a factory:
// Use a pre-created object 'service'. var service = new DataService(); SimpleIoc.Default.Register<IDataService>(() => service); // Create an instance and pass params to a ctor. var param1 = true; var param2 = "Hello world"; SimpleIoc.Default.Register<MainViewModel>(() => new MainViewModel(param1, param2));
Example: Force the immediate creation of an object at registration. It may be useful, for example, for a Settings object that needs to load settings as soon as the app starts:
// example #1 SimpleIoc.Default.Register<IDataService, DataService>(true); // example #2 SimpleIoc.Default.Register<MainViewModel>(true); // example #3 var service = new DataService(); SimpleIoc.Default.Register<IDataService>(() => service, true); // example #4 SimpleIoc.Default.Register<MainViewModel>(() => new MainViewModel(param1, param2), true);
Example: Register a class or an interface with a key. It allows for having multiple instances of the same class or interface inside the IoC container. The corresponding instance needs to be retrieved with the same key:
SimpleIoc.Default.Register<MainViewModel>(() => new MainViewModel(), "UniqueKey"); SimpleIoc.Default.Register<MainViewModel>(() => new MainViewModel(), "AnotherUniqueKey");
Example: Get a default instance for the MainViewModel class and the IDataService interface:
var instance = SimpleIoc.Default.GetInstance<MainViewModel>(); var service = SimpleIoc.Default.GetInstance<IDataService>();
Example: Get a keyed instance. Keyed instances may be useful if you need multiple instances of the same type. Keep in mind that all instances are cached. If you want to remove the instance from the cache, you need to unregister it using the same key.
// Use the same key for registration and for getting an instance. SimpleIoc.Default.Register<IDataService>(() => new DataService, "key1"); var specificInstance = SimpleIoc.Default.GetInstance<IDataService>("key1"); // get the instance with key1
// Do not pass any key to registration. A new instance is created for the key1. SimpleIoc.Default.Register<IDataService, DataService>(); var keyedInstance = SimpleIoc.Default.GetInstance<IDataService>("key1"); // create a new instance
SimpleIoc takes care of creating the necessary dependencies and composing them.
// MainViewModel has two dependecies. public MainViewModel(IDataService dataService, INavigationService navigationService) { this.dataService = dataService; this.navigationService = navigationService; } ... static ViewModelLocator() { // Register the services (our dependencies). SimpleIoc.Default.Register<IDataService, DataService>(); SimpleIoc.Default.Register<INavigationService, () => new NavigationService()>(); // Register the MainViewModel. SimpleIoc.Default.Register<MainViewModel>(); } ... public MainViewModel Main { // Create an instance of MainViewModel (if it's not already in cache). Before creating the instance though, // SimpleIoc creates the dependecies of MainViewModel: DataService and NavigationService. get { return SimpleIoc.Default.GetInstance<MainViewModel>(); } }
Constructor injection:
Property injection:
Example: DialogService property injection:
public class MainViewModel : ViewModelBase { private readonly IDataService dataService; public IDialogService DialogService { get { return SimpleIoc.Default.GetInstance<IDialogService>(); } } public MainViewModel(IDataService dataService) { this.dataService = dataService; } }
The Unregister method:
Example: Unregister the MainViewModel class and the IDialogService interface:
SimpleIoc.Default.Unregister<MainViewModel>(); SimpleIoc.Default.Unregister<IDialogService>();
Example: Unregister an instance identified by the key1:
SimpleIoc.Default.Unregister<IDataService>("key1");
Example: Unregister the 'this' instance:
SimpleIoc.Default.Unregister<IDialogService>(this);
Example: Register and unregister the current page as a dialog service during navigation events:
public sealed partial class MainPage : IDialogService { ... protected override void OnNavigatedTo(NavigationEventArgs args) { SimpleIoc.Default.Register<IDialogService>(() => this); base.OnNavigatedTo(args); } protected override void OnNavigatedFrom(NavigationEventArgs args) { SimpleIoc.Default.Unregister(this); base.OnNavigatedFrom(args); } }
Example: Check if a class or an interface is registered using the IsRegistered method. Also, check if a class has at least one instance created using the ContainsCreated method:
SimpleIoc.Default.Register<IDataService, DataService>(); var test1 = SimpleIoC.Default.IsRegistered<IDataService>(); // true var test2 = SimpleIoC.Default.ContainsCreated<IDataService>(); // false var instance = SimpleIoC.Default.GetInstance<IDataService>(); var test3 = SimpleIoC.Default.ContainsCreated<IDataService>(); // true
Example: Return existing instances using the GetAllCreatedInstances method:
SimpleIoc.Default.Register<IDataService, DataService>(); var allInstances = SimpleIoc.Default.GetAllCreatedInstances<IDataService>(); // no instances returned var instance1 = SimpleIoc.Default.GetInstance<IDataService>("key1"); var instance2 = SimpleIoc.Default.GetInstance<IDataService>("key2"); allInstances = SimpleIoc.Default.GetAllCreatedInstances<IDataService>(); // two instances returned
Keep in mind that the GetAllInstances method does force the creation of one default instance per registered class/interface.
SimpleIoc.Default.Register<IDataService, DataService>(); var allInstances = SimpleIoc.Default.GetAllInstances<IDataService>(); // one instance returned
The attribute PreferredConstructor:
public class DataService { public DataService() { } [PreferredConstructor] public DataService(IAnotherService another) { } }
// Define the ServiceLocator. ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); // Use the ServiceLocator. ServiceLocator.Current.GetInstance<IDataService>(); // The above line of code is an equivalent to the following one: SimpleIoc.Default.GetInstance<IDataService>();
Example: Register to listen for messages:
public MessageRecipient() { // Listen for messages of type String. Messenger.Default.Register<string>(this, HandleStringMessage); // Listen for messages of type CustomMessage. Messenger.Default.Register<CustomMessage>(this, HandleCustomMessage); // Listen for messages of type NotificationMessage<Invoice>. Messenger.Default.Register<NotificationMessage<Invoice>>(this, HandleInvoiceMessage); private void HandleStringMessage(string message) { /*...*/ } private void HandleCustomMessage(CustomMessage message) { /*...*/ } private void HandleInvoiceMessage(NotificationMessage<Invoice> message) { /*...*/ } // Listen for messages of type NotificationMessage<Invoice> and handle them using a lambda. Messenger.Default.Register<NotificationMessage<Invoice>>(this, message => { /*...*/ }); }
Example: Send messages:
// Send a message of a custom type. var msg = new CustomMessage(); Messenger.Default.Send(msg); // Send a message of a built-in type NotificationMessage. // - selectedInvoice is a payload. // - InvoiceSelectedNotification is a string containing an instruction for the receiver. var msg = new NotificationMessage<Invoice>( selectedInvoice, InvoiceSelectedNotification); Messenger.Default.Send(msg); // An overload that passes the message sender. // !!! Remember not to store the sender reference as it will create a memory leak. var msg = new NotificationMessage<Invoice>( this, selectedInvoice, InvoiceSelectedNotification); Messenger.Default.Send(msg);
Example: Unregister the message handling method(s):
// Unregister all methods of the 'this' recipient. Messenger.Default.Unregister(this); // Unregister a specific method. HandleMessage is a delegate of the method. Messenger.Default.Unregister<IMessage>(this, HandleMessage);
Example: Use a token to send and receive messages:
// Register and listen for messages. class MessageRecipient { // The token has to be unique. It can be anything (a string, an instance of a custom class, etc.) public static readonly Guid Token = Guid.NewGuid(); ... Messenger.Default.Register<NotificationMessage>(this, Token, HandleNotification); ... private void HandleNotification(NotificationMessage message) { /*...*/ } } // Send a message. Only the recipients who registered to listen for messages with the given token // will receive this message. Messenger.Default.Send(new NotificationMessage("DoSomething"), MessageRecipient.Token); // Unregister. Messenger.Default.Unregister<IMessage>(this, Token); // all handlers Messenger.Default.Unregister<IMessage>(this, Token, HandleMessage); // a specific handler
There are two strategies of binding Views and ViewModels:
Example: Bind a View to MainViewModel using the ViewModelLocator:
1. Instantiate the ViewModelLocator as a global resource in App.xaml:
<Application.Resources> <vm:ViewModelLocator x:Key="Locator" /> </Application.Resources>
-or-
<Application.Resources> <ResourceDictionary> <vm:ViewModelLocator x:Key="Locator" /> </ResourceDictionary> </Application.Resources>
2. Expose the most important ViewModels as ViewModelLocator's public properties:
public class ViewModelLocator { public MainViewModel Main { get; private set; } // ... }
3. Bind to the ViewModelLocator's Main property in the View:
<... DataContext="{Binding Main, Source={Locator}}">
Not all ViewModels should be declared in the ViewModelLocator. It depends on how long they need to be alive, when they need to be created, and so on.
4. Register services conditionally:
public ViewModelLocator() { if (ViewModelBase.IsInDesignModeStatic) { SimpleIoc.Default.Register<IDataService, DesignDataService>(); } else { SimpleIoc.Default.Register<IDataService, DataService>(); } SimpleIoc.Default.Register<IDialogService, DialogService>(); SimpleIoc.Default.Register<INavigationService, NavigationService>(); SimpleIoc.Default.Register<MainViewModel>(); }
Snippets are grouped by function:
Examples:
VS built-in code snippets:
There are three versions of MVVM Light in NuGet: