Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Expression Blendable Silverlight View Model Communication

0.00/5 (No votes)
26 Sep 2010 1  
Easily implement two-way communication between Master and Child View Models that works with Microsoft Expression Blend

Easy 'Blendable' View Model Communication

Live example at this link.

In the article, Silverlight View Model Communication, we covered View Model Communication, but it was only one way.

In the Silverlight Debate Forum project, the developers asked for two way communication, and they wanted it to be 'blendable', meaning, they could use Microsoft Expression Blend, to easily select ICommands and set properties in any View Model control, from any View Model control.  

The end result, allows you to call any Master or Child control, from any Master or Child control.

How It Works

The diagram above explains how this works. If you find it confusing, don't worry, we will try to cover this in a few different ways.

The Child1ViewModel has an instance of MainPageViewModel in it's View Model. it is able to use this instance to call any ICommand, or read and set any Properties, in the Main Page View Model.

Also, the Main Page View Model contains the View Model of the other Child View Models, so a Child View Model is able to communicate through the Main Page View Model, to call any ICommand, or read and set any Properties, in any of the other Child View Models!

The Code - The Child Control

The code for the Child View Model is as follows:

public class Child1ViewModel : INotifyPropertyChanged
{
    public Child1ViewModel()
    {
        Child1RaiseCommand = new DelegateCommand(Child1Raise, CanChild1Raise);
    }
    
    public ICommand Child1RaiseCommand { get; set; }
    public void Child1Raise(object param)
    {
        Message = (String)param;
    }
    
    private bool CanChild1Raise(object param)
    {
        return true;
    }
    
    private string _Message;
    public string Message
    {
        get { return _Message; }
        set
        {
            if (Message == value)
            {
                return;
            }
            _Message = value;
            this.NotifyPropertyChanged("Message");
        }
    }
    
    private MainPageViewModel _objMainPageViewModel;
    public MainPageViewModel objMainPageViewModel
    {
        get { return _objMainPageViewModel; }
        set
        {
            if (objMainPageViewModel == value)
            {
                return;
            }
            _objMainPageViewModel = value;
            this.NotifyPropertyChanged("objMainPageViewModel");
        }
    }
    
    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    
    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
    #endregion
}

Notice that it contains:

  • A Message Property to display the message set by the Child1RaiseCommand ICommand
  • A Property to hold an instance of MainPageViewModel (objMainPageViewModel)

The blue box surrounding the objMainPageViewModel property shows how it allows us to navigate through that property to call an ICommand on the Main Page View Model, or another Child View Model.

However, it is important that only the DataContext for the XAML page is set to point to the View Model for the Child control. If you set the Data Context for any other element in the XAML of the control, the communication will not work.

The Code - The Main Control

The code for the Main Page View Model is as follows:

public class MainPageViewModel : INotifyPropertyChanged
{
    public MainPageViewModel()
    {
        RaiseCommand = new DelegateCommand(Raise, CanRaise);
        
        // Create instances of each ViewModel for each Child Control
        // Set an instance of the MainPage View Model in each 
        // View Model for each Child Control
        // The Child Controls onb the View of The Main Page will
        // be bound to these properties
        objChild1ViewModel = new Child1ViewModel();
        objChild1ViewModel.objMainPageViewModel = this;
        
        objChild2ViewModel = new Child2ViewModel();
        objChild2ViewModel.objMainPageViewModel = this;
    }
    
    #region RaiseCommand
    public ICommand RaiseCommand { get; set; }
    public void Raise(object param)
    {
        Message = (String)param;
    }
    
    private bool CanRaise(object param)
    {
        return true;
    }
    #endregion
    
    private string _Message;
    public string Message
    {
        get { return _Message; }
        private set
        {
            if (Message == value)
            {
                return;
            }
            _Message = value;
            this.NotifyPropertyChanged("Message");
        }
    }
    
    private Child1ViewModel _objChild1ViewModel;
    public Child1ViewModel objChild1ViewModel
    {
        get { return _objChild1ViewModel; }
        set
        {
            if (objChild1ViewModel == value)
            {
                return;
            }
            _objChild1ViewModel = value;
            this.NotifyPropertyChanged("objChild1ViewModel");
        }
    }
    
    private Child2ViewModel _objChild2ViewModel;
    public Child2ViewModel objChild2ViewModel
    {
        get { return _objChild2ViewModel; }
        set
        {
            if (objChild2ViewModel == value)
            {
                return;
            }
            _objChild2ViewModel = value;
            this.NotifyPropertyChanged("objChild2ViewModel");
        }
    }
    
    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    
    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
    #endregion
}

Notice that it contains:

  • A Property to hold an instance of each Child View Model (objChild1ViewModel and objChild2ViewModel)
  • It sets an instance of itself when it initializes each Child View Model Property, in its constructor (objChild1ViewModel.objMainPageViewModel = this)

The diagram above shows how we are now able to call ICommands in the Child View Models.

The thing that ties it all together, is that in Microsoft Expression Blend, we place a Child Control on the Main Page...

In the Properties for the control, we select Advanced options.

We select Data Binding...

We bind the DataContext for the Child Control to the property in the Main Page View Model.

We also set it to TwoWay binding.

It Is Now Blendable

In the designer in Expression Blend, if we click on a Button in the Child Control...

In the Properties, we select Advanced options next to Command (under Miscellaneous).

We can then navigate to any ICommand or Property in any View Model in the application.

Other Methods

There are other methods to achieve communication between View Models. There are various MVVM frameworks that provide Messaging. The advantage of these frameworks is that they are loosely-coupled. However, for the Silverlight Debate Forum project, if we require changes in the future, we will just make any needed changes to the code.

The primary advantage for that project is that since it uses MEF to dynamically load the Views, a Designer will be able to implement the View Model Communication without needing to touch any code. Everything the Designer needs will be available in Expression Blend.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here