Programming Reference

ViewModelBase

This class serves as the base class for all your view-models.  It has a single property, IsInDesignMode, which returns true when a view that is bound to this view-model is being edited in a designer, which can either be Visual Studio or Expression Blend. To support designability, also referred to as Blendability, check this property in your view-model in order to supply data that will be displayed in design view.  This makes it much easier for a designer, or a developer who is playing designer, to see a visual representation that is populated with sample or dummy data.  This is important because live data will only be shown at runtime, and some controls, such as labels, cannot be easily manipulated by design tools unless there is some design-time data to hold it in place.

public abstract class ViewModelBase
{
    // Allows you to provide data at design-time (Blendability)
    public bool IsInDesignMode
    {
        get
        {
            return DesignerProperties.IsInDesignTool;
        }
    }
}

ModelBase<TModel>, ViewModelBase<TViewModel>

The toolkit includes two base classes, ModelBase<TModel> and ViewModelBase<TViewModel>, which support two-way data binding by implementing INotifyPropertyChanged.  They do this by providing a NotifyPropertyChanged method that accepts a lambda expression indicating the property that has been changed. This is to address one of the drawbacks of the PropertyChanged event, which is that it accepts a string for the property name. However, because NotifyPropertyChanged accepts a lambda expression, it provides a compile-time check for the property name, which can catch errors when you change the property name and forget to change it in the call to NotifyPropertyChanged.

Another benefit of the NotifyPropertyChanged method is that it is always guaranteed to fire on the UI thread, because the InternalNotifyPropertyChanged method asks the current Dispatcher to see if we’re on the UI thread and, if not, calls BeginInvoke to marshal the call over to the UI thread.  This behavior is required when you are setting properties asynchronously from a worker thread.

public abstract class ModelBase<TModel> : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged
    {
        add { propertyChanged += value; }
        remove { propertyChanged -= value; }
    }
    protected PropertyChangedEventHandler propertyChanged;

    protected virtual void NotifyPropertyChanged<TResult>
        (Expression<Func<TViewModel, TResult>> property)
    {
        // Fire PropertyChanged event
        BindingHelper.NotifyPropertyChanged(property, this, propertyChanged);
    }
    // Other members elided for clarity ...
}
public abstract class ViewModelBase<TViewModel> : ViewModelBase, INotifyPropertyChanged { ... }
internal static class BindingHelper
{
    // Defined as virtual so you can override if you wish
    public static void NotifyPropertyChanged<TModel, TResult>
        (Expression<Func<TModel, TResult>> property,
        object sender, PropertyChangedEventHandler propertyChanged)
    {
        // Convert expression to a property name
        string propertyName = ((MemberExpression)property.Body).Member.Name;

        // Fire notify property changed event
        InternalNotifyPropertyChanged(propertyName, sender, propertyChanged);
    }

    public static void InternalNotifyPropertyChanged(string propertyName, 
        object sender, PropertyChangedEventHandler propertyChanged)
    {
        if (propertyChanged != null)
        {
            // Always fire the event on the UI thread
            if (Deployment.Current.Dispatcher.CheckAccess())
            {
                propertyChanged(sender, new PropertyChangedEventArgs(propertyName));

            }
            else
            {
                Deployment.Current.Dispatcher.BeginInvoke(() => propertyChanged
                    (sender, new PropertyChangedEventArgs(propertyName)));
            }
        }
    }
}

Here is an example of calling NotifyPropertyChanged from a property setter in a view-model.

private bool canLoad;
public bool CanLoad
{
    get { return canLoad; }
    set
    {
        canLoad = value;
        NotifyPropertyChanged(m => m.CanLoad);
    }
}

Speaking of asynchronous programming, ViewModelBase<TViewModel> also includes a Notify method that fires a notification event by marshaling it to the UI thread if necessary.  Further down this page you’ll learn about using notification events to handle two-way communication between a view and its view-model.

protected void Notify
    (EventHandler<NotificationEventArgs> handler,
    NotificationEventArgs e)
{
    if (handler != null)
    {
        InternalNotify(() => handler(this, e));
    }
}

protected void Notify<TOutgoing>
    (EventHandler<NotificationEventArgs<TOutgoing>> handler,
    NotificationEventArgs<TOutgoing> e)
{
    if (handler != null)
    {
        InternalNotify(() => handler(this, e));
    }
}

protected void Notify<TOutgoing, TIncoming>
    (EventHandler<NotificationEventArgs<TOutgoing, TIncoming>> handler,
    NotificationEventArgs<TOutgoing, TIncoming> e)
{
    if (handler != null)
    {
        InternalNotify(() => handler(this, e));
    }
}

private void InternalNotify(Action method)
{
    // Always fire the event on the UI thread
    if (UIDispatcher.Current.CheckAccess())
        method();
    else
        UIDispatcher.Current.BeginInvoke(method);
}

ViewModelDetailBase<TViewModel, TModel>

This base class implements IEditableObject to support editing an entity and either committing or rolling back changes.  A typical scenario would be an Edit dialog or page that will commit changes when the user clicks OK or roll them back when the user clicks Cancel.  Calling the edit methods will only be necessary if editing is not already enabled by another means, such as a data form or in the base class of your model entities, as is the case with RIA Services.  The way ViewModelDetailBase does this is with an Model property that will either point to a cloned version of the entity (on BeginEdit) or to the original version (on CancelEdit).  In EndEdit it will copy values from the cloned object over to the original.

public abstract class ViewModelDetailBase<TViewModel, TModel>
    : ViewModelBase<TViewModel>, IEditableObject
    where TModel : INotifyPropertyChanged
{
    public TModel Model
    {
        get { return model; }
        set
        {
            model = value;
            BindingHelper.InternalNotifyPropertyChanged("Model",
                this, base.propertyChanged);
        }
    }
    private TModel model;

    // Other members elided for clarity ...

    private TModel Original;
    private TModel Copy;

    public void BeginEdit()
    {
        // Throw an exception if Entity not supplied
        if (Model == null)
        {
            throw new InvalidOperationException("Entity must be set");
        }

        // Copy entity
        Original = Model;
        Copy = Model.Clone();

        // Point entity to the copy
        Model = Copy;
    }

    public void CancelEdit()
    {
        // Point entity to original
        Model = Original;
    }

    public void EndEdit()
    {
        // Tranfer values from copy to original
        Copy.CopyValuesTo(Original);

        // Point entity to original
        Model = Original;
    }
}

The Clone and CopyValuesTo methods are implemented as extension methods in the Extensions class and can be brought into scope by inserting a using directive for the namespace, SimpleMvvmToolkit.ModelExtensions.  Clone uses the DataContractSerializer to serialize the object to and from a memory stream. It will work with entities that do not have the [DataContract] attribute by serializing all public properties.

public static class Extensions
{
    public static T Clone<T>(this T obj)
    {
        T copy = default(T);
        using (MemoryStream stream = new MemoryStream())
        {
            var ser = new DataContractSerializer(typeof(T));
            ser.WriteObject(stream, obj);
            stream.Position = 0;
            copy = (T)ser.ReadObject(stream);
        }
        return copy;
    }

    public static void CopyValuesTo<T>(this T source, T dest)
    {
        var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => p.CanRead && p.CanWrite);

        foreach (var property in properties)
        {
            if (property.GetSetMethod() == null) continue;
            property.SetValue(dest, property.GetValue(source, null), null);
        }
    }
}

There is also an AssociateProperties method that will propagate changes from a model property to a view-model property, so that updates to the model will be reflected in UI elements that are bound to the corresponding view-model properties.

protected virtual void AssociateProperties<TModelResult, TViewModelResult>
    (Expression<Func<TModel, TModelResult>> modelProperty,
        Expression<Func<TViewModel, TViewModelResult>> viewModelProperty)
{
    // Convert expressions to a property names
    string modelPropertyName = ((MemberExpression)modelProperty.Body).Member.Name;
    string viewModelPropertyName = ((MemberExpression)viewModelProperty.Body).Member.Name;

    // Propagate model to view-model property change
    Model.PropertyChanged += (s, ea) =>
    {
        if (ea.PropertyName == modelPropertyName)
        {
            BindingHelper.InternalNotifyPropertyChanged(viewModelPropertyName,
                this, base.propertyChanged);
        }
    };
}

Here is an example of a CustomerViewModel class that transforms properties on a Customer model.  FirstName and LastName are exposed as a single CustomerName property, and IsActive is used to expose an OrdersVisibility property.  CustomerViewModel calls AssociateProperties in the setter of a Customer property, so that changes to the Customer model properties will be reflected in UI elements that are bound to the CustomerName and OrdersVisibility properties.

public class CustomerViewModel : ViewModelDetailBase<CustomerViewModel, Customer>
{
    public Customer Customer
    {
        get
        {
            return Model;
        }
        set
        {
            Model = value;

            // Associate model and view-model properties
            AssociateProperties(m => m.FirstName, vm => vm.CustomerName);
            AssociateProperties(m => m.LastName, vm => vm.CustomerName);
            AssociateProperties(m => m.IsActive, vm => vm.OrdersVisibility);
        }
    }

    public string CustomerName
    {
        get
        {
            // Concatenate first and last name
            return string.Format("{0} {1}",
                Model.FirstName, Model.LastName);
        }
    }

    public Visibility OrdersVisibility
    {
        get
        {
            // Show orders only for active customers
            return Model.IsActive ? Visibility.Visible : Visibility.Collapsed;
        }
    }
}

NotificationEventArgs

When a view-model wishes to communicate with a view, it should do so in a loosely coupled manner.  The view-model should not reference the view or be aware of it in any way.  This presents somewhat of a quandary for many developers.  One approach is to use a message bus for communication between the view-model and the view.  To my mind, that is a bit too loose, because the view already holds a reference to the view-model.  Another approach is to use a service represented by an interface.  The view-model then holds on to a reference to the view via the service interface.  This is better than a direct reference but seems still too tight to me.  I prefer to use events as the communication mechanism because they offer finer granularity than interfaces and are more direct than a message bus.  Plus they are easy for developers to understand and implement.

There are three versions of NotificationEventArgs. The non-generic version simply has a string Message property.  There also is a generic version that accepts a <TOutgoing> type argument, which is an additional data payload passed by the view-model back to the view.  This can be an Exception or any other type.  And there another generic version which has a Completed property that is an Action<TIncoming>, which the view-model sets to a completion callback method, so that the view can call back the view-model and pass a data payload.

public class NotificationEventArgs : EventArgs
{
    public NotificationEventArgs() { }
    public NotificationEventArgs(string message)
    {
        Message = message;
    }

    // Message
    public string Message { get; protected set; }
}

public class NotificationEventArgs<TOutgoing> : NotificationEventArgs
{
    public NotificationEventArgs() { }
    public NotificationEventArgs(string message) : base(message) { }
    public NotificationEventArgs(string message, TOutgoing data)
        : this(message)
    {
        Data = data;
    }

    // Data
    public TOutgoing Data { get; protected set; }
}

public class NotificationEventArgs<TOutgoing, TIncoming> : NotificationEventArgs<TOutgoing>
{
    public NotificationEventArgs() { }
    public NotificationEventArgs(string message) : base(message) { }
    public NotificationEventArgs(string message, TOutgoing data)
        : base(message, data) { }
    public NotificationEventArgs(string message, TOutgoing data, Action<TIncoming> completed)
        : this(message, data)
    {
        Completed = completed;
    }
        
    // Completion callback
    public Action<TIncoming> Completed { get; protected set; }
}

Here is an example of a view-model firing a one-way notification event.

public class ProductListViewModel : ViewModelBase<ProductListViewModel>
{
    // By convention we'll suffix each notification event with 'Notice'
    public event EventHandler<NotificationEventArgs<Exception>> ErrorNotice;

    private void NotifyError(string message, Exception error)
    {
        // Notify view of an error
        if (ErrorNotice != null)
        {
            ErrorNotice(this, new NotificationEventArgs<Exception>(message, error));
        }
    }
}

However, we can make this more concise by taking advantage of the Notify method in ViewModelBase, which checks if the event is null (meaning it has no subscribers) and transparently marshals the call to the UI thread if necessary.

private void NotifyError(string message, Exception error)
{
    // Notify view of an error
    Notify(ErrorNotice, new NotificationEventArgs<Exception>(message, error));
}

Here is an example of a view-model firing a two-way notification event.

public class ProductListViewModel : ViewModelBase<ProductListViewModel>
{
    // By convention we'll suffix each notification event with 'Notice'
    public event EventHandler<NotificationEventArgs<bool, bool>> ProductAvailableNotice;
 
    private void ProductAvailable(bool available, Exception error)
    {
        // Notify view that product is available
        Notify(ProductAvailableNotice, new NotificationEventArgs<bool, bool>
            (null, available, 
            confirm => { if (confirm) /* place order */; }));
    }
}

The view can respond handle the event in its code-behind class, supplying the <TIncoming> argument, which in this case is a boolean indicating that the user confirmed the order.

public partial class ProductListView : UserControl
{
    // Reference view model
    ProductListViewModel vm;

    public ProductListView()
    {
        InitializeComponent();

        // Get model from data context
        vm = (ProductListViewModel)DataContext;

        // Subscribe to notifications from the model
        vm.ErrorNotice += OnErrorNotice;
        vm.ProductAvailableNotice += OnProductAvailableNotice;
    }

    void OnErrorNotice(object sender, NotificationEventArgs<Exception> e)
    {
        MessageBox.Show(e.Message, "Error", MessageBoxButton.OK);
        Debug.WriteLine(e.Data.ToString());
    }

    void OnProductAvailableNotice(object sender, NotificationEventArgs<bool, bool> e)
    {
        // Product is available
        if (e.Data)
        {
            // Show OrderProductView dialog
            OrderProductView orderProductView = new OrderProductView();
            var orderProductVm = (OrderProductViewModel)orderProductView.DataContext;
            orderProductVm.Product = vm.SelectedProduct;
            orderProductView.Closed += (s, ea) =>
            {
                if (orderProductView.DialogResult == true)
                {
                    // Notify view model to order product
                    e.Completed(true);
                }
            };
            orderProductView.Show();
        }
        else
        {
            MessageBox.Show("Product is unavailable.",
                "Product Availability", MessageBoxButton.OK);
        }
    }
}

DelegateCommand

SimpleMvvmToolkit also contains generic and non-generic versions of a DelegateCommand class.  This is typically used to supply an ICommand property on the view-model, which the view can reference to bind the Command property of a ButtonBase-derived class.  This is to support scenarios where you might have a method on your view-model that accepts a parameter that is not already exposed as a property on the view-model.

public class DelegateCommand<T> : ICommand
{
    private Func<T, bool> canExecute;
    private Action<T> executeAction;

    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<T> executeAction,
        Func<T, bool> canExecute)
    {
        this.executeAction = executeAction;
        this.canExecute = canExecute;
    }

    public DelegateCommand(Action<T> executeAction)
    {
        this.executeAction = executeAction;
        this.canExecute = x => true;
    }

    public void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    }

    public bool CanExecute(object parameter)
    {
        if (parameter == null) return true;
        T param = ConvertParameter(parameter);
        return canExecute == null ? true : canExecute(param);
    }

    public void Execute(object parameter)
    {
        T param = ConvertParameter(parameter);
        executeAction(param);
    }

    // Convert parameter to expected type, parsing if necessary
    private T ConvertParameter(object parameter)
    {
        string exceptionMessage = string.Format("Cannot convert {0} to {1}",
            parameter.GetType(), typeof(T));

        T result = default(T);
        if (parameter != null && parameter.GetType() == typeof(T))
        {
            result = (T)parameter;
        }
        else if (parameter is string)
        {
            MethodInfo mi = (from m in typeof(T).GetMethods(BindingFlags.Static | BindingFlags.Public)
                                where m.Name == "Parse" && m.GetParameters().Count() == 1
                                select m).FirstOrDefault();
            if (mi != null)
            {
                try
                {
                    result = (T)mi.Invoke(null, new object[] { parameter });
                }
                catch (Exception ex)
                {
                    if (ex.InnerException != null) throw ex.InnerException;
                    else throw new InvalidCastException(exceptionMessage);
                }
            }
        }
        else
        {
            throw new InvalidCastException(exceptionMessage);
        }
        return result;
    }
}

Use the mvvmvommand code snippet to insert a command that will execute a method on the ViewModel.  The ctor for DelegateCommand<T> also accepts a delegate for a method that accepts T and returns bool. Notice that the setter for the Amount property calls the RaiseCanExecuteChanged method so that the CanExecute method will be evaluated and the button will be enabled or disabled depending on whether the method returns true or false.

#region Properties

private int amount;
public int Amount
{
    get { return amount; }
    set
    {
        amount = value;
        NotifyPropertyChanged(m => m.Amount);

        // Raise can execute changed event on command
        AddCommand.RaiseCanExecuteChanged();
    }
}

private int total;
public int Total
{
    get { return total; }
    set
    {
        total = value;
        NotifyPropertyChanged(m => m.Total);
    }
}

#endregion

#region Methods

void Add(int num)
{
    Total = Amount + num;
}

bool CanAdd(int num)
{
    return Amount > 0;
}

#endregion

#region Commands

private DelegateCommand<int> addCommand;
public DelegateCommand<int> AddCommand
{
    get { return addCommand ?? (addCommand = new DelegateCommand<int>(Add, CanAdd)); }
    private set { addCommand = value; }
}

#endregion

The view can then bind the Command of a Button to the AddCommand on the view-model, specifying a CommandParameter to pass to the Add method.

<Button Content="Add 1"
        Command="{Binding AddCommand}"
        CommandParameter="1"/>

Here is a sample application that demonstrates the use of commands with Simple Mvvm Toolkit.

Blend EventTrigger / Action

While I support this approach, I find that it is not needed most of the time because you will generally have controls in the view that are bound to properties on the view-model. A parameterless method on the view-model can simply reference these properties, freeing you to use an blend-style event trigger that uses a CallMethodAction.  This relieves you from having a bunch of code in your view-model just to support command-binding.  Event triggers can respond to any event, not just click, and there’s no need to call RaiseCanExecuteChanged.

Here is a XAML snippet that calls the LoadProducts method on the view-model on the SelectionChanged event of a combo box.

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
<!-- Bind ItemsSource to Categories -->
<!-- Bind SelectedItem to SelectedCategory -->
<ComboBox Height="23" Name="categoriesComboBox" Width="149" 
            DisplayMemberPath="CategoryName" 
            ItemsSource="{Binding Path=Categories}" 
            SelectedItem="{Binding Path=SelectedCategory, Mode=TwoWay}" Margin="0,5">
    <!-- Call LoadProducts on SelectionChanged event -->
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <ei:CallMethodAction 
                TargetObject="{Binding}"
                MethodName="LoadProducts"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ComboBox>

The toolkit comes with two XML code snippets you can use to insert namespaces and the event trigger: mvvmxmlns and mvvmtrigger.  However, Visual Studio does not support using code snippets in a XAML file, you you need to open the file with the Visual Studio XML Editor (right-click, Open With, XML Text Editor).  Then place the cursor where you want to use the snippet, right-click and select Insert Snippet).

MessageBus

Sometimes you need to pass messages among view-models in your application.  A good example would be when you want to navigate to a particular view based on some business logic.  It would not be a good idea to reference the main view-model directly from another view-model.  Doing so would create interdependencies between view-models that would be difficult to maintain (a phenomenon referred to as spaghetti code).  This is where a message bus (also called an event mediator or aggregator) comes in handy. The CustomerViewModel, for example, can then send a message to the message bus using a specific token, and the MainPageViewModel can subscribe to receive a message whenever someone sends a message with this same token to the message bus.  Message tokens are simply strings that can be defined as constants in a class.

To make it easy to send and receive messages via the MessageBus, ViewModelBase<TViewModel> has two helper methods:  RegisterToReceiveMessages and SendMessage. Here is a Save method in the CustomerViewModel that posts a message to the MessageBus using a token defined as a string constant in the MessageTokens class.  The message content is simply a NotificationEventArgs object, which in this case simply passes the name of the page we want to navigate to.

public void Save()
{
    SendMessage(MessageTokens.Navigation,
        new NotificationEventArgs(PageNames.Home));
}

The MainPageViewModel subscribes to receive messages with the MessageTokens.Navigation token.  When a message arrives at the MessageBus with this token, the MessageBus will call the method supplied to the Register method.  In this case the OnNavigationRequested method will be called, which will navigate to the specified page.

public class MainPageViewModel : ViewModelBase<MainPageViewModel>
{
    public MainPageViewModel()
    {    
        RegisterToReceiveMessages(MessageTokens.Navigation, OnNavigationRequested);
    }

    void OnNavigationRequested(object sender, NotificationEventArgs e)
    {
        Navigate(e.Message);
    }
}

Because the MessageBus implements a leak-proof eventing model, there is no need for the MainPageViewModel to unregister for receiving messages.  Message receivers are weakly referenced by the MessageBus, so they can be garbage collected at any time.

That’s all there is to it!  As with direct notifications, you can pass additional data by specifying a TOutgoing argument on NotificationEventArgs.  And you can even have the message recipient call back the sender by passing in a callback method with a TIncoming argument.  Strongly-typed, loosely-coupled two-way communication.  Cool.

ViewModelLocator

There are many ways to create ViewModels.  But for a better design-time experience it’s a good idea to bind the DataContext of the View directly to a ViewModel.  There are times, however, when you want to supply a service agent to the ViewModel’s constructor, which means you cannot create the ViewModel in the XAML of the View.  What you need to solve this problem is a ViewModelLocator.  Luckily for you, the toolkit comes with a Visual Studio item template.  Simply add a new item to the project and select SimpleMvvmViewModelLocator from the dialog.  Then use the mvvmlocator code snippet to insert a property that creates a ViewModel on demand while supplying a service agent to the ViewModel’s ctor.

public class ViewModelLocator
{
    // Create CustomerViewModel on demand
    public CustomerViewModel CustomerViewModel
    {
        get
        {
            ICustomerServiceAgent serviceAgent = new MockCustomerServiceAgent();
            return new CustomerViewModel(serviceAgent);
        }
    }
}

An instance of the ViewModelLocator is stored in the resource dictionary of App.xaml and identified with a key of “Locator”.

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
             x:Class="SimpleMvvmSilverlight.App">
    <Application.Resources>
        <vm:ViewModelLocator xmlns:vm="clr-namespace:SimpleMvvmSilverlight"
            x:Key="Locator" />
    </Application.Resources>
</Application>

Then you need to bind the DataContext of the View using a StaticResource with the “Locator” key, specifying the CustomerViewModel property for the Path.

<UserControl x:Class="SimpleMvvmSilverlight8.CustomerView"
    DataContext="{Binding Source={StaticResource Locator}, Path=CustomerViewModel}">

ServiceAgentExportAttribute, IServiceAgentMetadata, AgentType

These classes support using Dependency Injection (also called Inversion of Control) to specify which service agent to use in a view-model locator.  This is useful for executing unit tests with mock data so that they run faster and do not depend on external factors such as the availability of services or data stores.  The simplest way to implement dependency injection is to use Managed Extensibility Framework (MEF), which ships with Silverlight out of the box.  The way you do this is to define a custom export attribute which includes a property you can use to as metadata to identify which class you want to materialize.  A full discussion of MEF is beyond the scope of this documentation, but you can find more information on my blog, including a screencast, slides and code samples.

The way you use these classes is to decorate service agents with the ServiceAgentExport attribute, passing the service agent interface as the contract type and an AgentType enum value (which can be Unspecified, Real or Mock).

[ServiceAgentExport(typeof(ICustomerServiceAgent), AgentType = AgentType.Mock)]
public class MockItemListServiceAgent : IItemListServiceAgent
{
    public void GetItems(Action<Item, Exception> completed)
    {
        // Use mock data for Customer ...
    }
}

You can then add an “injected” view-model locator using the SimpleMvvmViewModelInjectedLocator Visual Studio item template that comes with the toolkit.  This class as an AgentType property which unit tests can set to Mock. There is also a ServiceAgents property with an ImportMany MEF attribute.  It uses a Lazy<T, TMetadata> type to only get service agents with a particular AgentType used in its ServiceAgentExport attribute.  The constructor of the view-model asks MEF to set the ServiceAgents property.

public class InjectedViewModelLocator
{
    static InjectedViewModelLocator()
    {
        // Expose parts in the current XAP to MEF
        if (!DesignerProperties.IsInDesignTool)
            CompositionHost.Initialize(new DeploymentCatalog());
    }

    // TODO: Change agent type to Real
    private AgentType agentType = AgentType.Mock;
    public AgentType AgentType
    {
        get { return agentType; }
        set { agentType = value; }
    }

    public InjectedViewModelLocator()
    {
        // Inject service agents at runtime
        if (!DesignerProperties.IsInDesignTool)
        {
            CompositionInitializer.SatisfyImports(this);
            Debug.Assert(this.ItemListViewModel != null,
                string.Format("No IItemListServiceAgent has ServiceAgentExport with AgentType = {0}", agentType));
        }
    }

    // Create MainPageViewModel on demand
    public MainPageViewModel MainPageViewModel
    {
        get { return new MainPageViewModel(); }
    }

    // Create ItemListViewModel on demand
    [ImportMany]
    public Lazy<IItemListServiceAgent, IServiceAgentMetadata>[] ItemListServiceAgents { get; set; }
    public ItemListViewModel ItemListViewModel
    {
        get
        {
            var serviceAgent = ItemListServiceAgents
                .Where(sa => sa.Metadata.AgentType == agentType).FirstOrDefault();
            ItemListViewModel viewModel = null;
            if (serviceAgent != null) viewModel = new ItemListViewModel(serviceAgent.Value);
            else if (DesignerProperties.IsInDesignTool) viewModel = new ItemListViewModel();
            return viewModel;
        }
    }
}

You can then add a Silverlight Unit Test Application to your project (provided you’ve installed the Silverlight Toolkit) and create a test that sets AgentType on InjectedViewModelLocator to Mock before executing the test.  Here is an example which also plays nice with the asynchronous nature of the LoadItems mehod.  The unit test app requires that to run the app to execute the tests.

[TestClass]
public class ItemListViewModelTests : SilverlightTest
{
    // Mock data
    private List<Item> mockItems = MockItems.GetItems();

    // Add ViewModel field
    ItemListViewModel viewModel;

    // Initialize ViewModel
    public ItemListViewModelTests()
    {
        // Create locator
        var locator = new InjectedViewModelLocator();
        locator.AgentType = AgentType.Mock;

        // Get ViewModel
        this.viewModel = locator.ItemListViewModel;
        Assert.IsNotNull(viewModel, "ServiceAgent not injected for ViewModel");
    }

    [TestMethod, Asynchronous]
    public void LoadItemsTest()
    {
        // Completion flag
        bool completed = false;

        // Handle error
        viewModel.ErrorNotice += (s, ea) => Assert.Fail(ea.Data.Message);

        // Handle property change
        viewModel.PropertyChanged += (s, ea) =>
        {
            string propName = this.GetPropertyName<ItemListViewModel,
                ObservableCollection<Item>>(vm => vm.Items);
            if (ea.PropertyName == propName
                && viewModel.Items != null) completed = true;
        };

        // Call ViewModel method
        EnqueueCallback(() => viewModel.LoadItems());

        // Wait for completion with timeout
        int timeoutSeconds = 10; //Debugging: Timeout.Infinite
        this.EnqueueConditional(() => completed, timeoutSeconds);

        // Perform Asserts
        EnqueueCallback(() =>
            {
                // Categories has been set to 8
                Assert.IsNotNull(viewModel.Items);
                Assert.Equals(viewModel.Items.Count, 8);
            });

        // Complete test
        EnqueueTestComplete();
    }
}

Happy coding!

Last edited Aug 14, 2011 at 8:53 PM by tonysneed, version 19

Comments

alexrainman May 29, 2015 at 5:51 PM 
Hi Tony,

How can i make a command parameter dynamic?

Thank you for this toolkit, really cool stuff.

adolfo1981 Apr 13, 2012 at 5:49 PM 
I agree, this is one of the best and most well documented MVVM frameworks I have found. Flawless installation and very complete sample applications. I decided to use it for a big WPF application I'm building and it solves most of the issues I've run into, like communication between V and VM's, and Notifications in general, now I'll try to integrate it to Unity IoC Container now that I see Tony has added Dependency Injection Support!. I've also contacted Tony with some questions and he has been very helpful and supportive. We appreciate all the efforts you've put into this Tony!

genyded Feb 22, 2011 at 10:49 PM 
Hi Tony,

Very cool stuff! I am new to SL and MVVM, PRISM, MEF, UNITY, ... name your other flavor. With all the changes and samples that are based on any one of the 100,000 of them, this is the FIRST framework that made sense and actually worked "out of the box" on download. I know some have issues because I am running VWD Express, but no this one. Was able to get an app from scratch to work on teh 1st try and have never been able to with another SL, MVVM, or other download from anyone.

So - kudos on all that and your toolkit is very cool. It also covers ALL the needed aspects and then some. Great work!!!

Dale