We made a good progress in last part of the mediator article by removing the dependencies of any interface by registering the call back method and execute it by calling DynamicInvoke method here. But there is still one problem in it that it will call all the register call back method whenever we send a message from any class. There is no way to send message to specific client.
Now lets enhance a mediator class a bit and introduced a concept of message type. Now we can define the message type and register the call back method for that particular message. By doing this we have two advantages. First now we can define as may messages as we want, second we can specify the target of for specific message rather than broadcast that message to everywhere.
We created Dictionary for messages and call back methods.
new Dictionary<string, List<Action<object>>>();
We modified our register method little bit and now it accept the message type and the call back method. For simplicity we select message of string type, but we can use alternative approaches too. Our Register method simply check if there isn’t any entry for that message in the dictionary then create an empty list object, or if there is already one entry then simply add the new method to existing list. Here is our Register method.
{
if (!actions.ContainsKey(message))
{
actions[message] = new List<Action<object>>();
}
actions[message].Add(action);
}
Similarly at the time of sending the messages we first check if there is any call back method register for that particular message and if there is then call all of them one by one. Here is a code of Send message of mediator class.
{
if (actions.ContainsKey(message))
{
List<Action<object>> actionslist = actions[message];
foreach (var action in actionslist)
{
action.DynamicInvoke(param);
}
}
}
Here is complete code of our modified Mediator class.
using System.Collections.Generic;
namespace MediatorUserControl
{
public class Mediator
{
private Dictionary<string, List<Action<object>>> actions =
new Dictionary<string, List<Action<object>>>();
public Mediator()
{
}
public void Register(string message, Action<object> action)
{
if (!actions.ContainsKey(message))
{
actions[message] = new List<Action<object>>();
}
actions[message].Add(action);
}
public void Send(string message, object param)
{
if (actions.ContainsKey(message))
{
List<Action<object>> actionslist = actions[message];
foreach (var action in actionslist)
{
action.DynamicInvoke(param);
}
}
}
}
}
Now the main difference is we have to register the call back method with the message type. Here is a main view code to register the call back functions.
Mediator.Register("mymessage1", studentform.Notify);
Mediator.Register("mymessage1", studentlist.Notify);
Mediator.Register("mymessage2", studentform.AnotherNotify);
studentform.Mediator = Mediator;
studentlist.Mediator = Mediator;
Note that we register two different type of messages “mymessage1” and “mymessage2”. There is only one method register for “mymessage2”, but two methods register for “mymessage1”.
Here is a complete C# code of main view class.
using System.Windows;
namespace MediatorUserControl
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<Student> students = new ObservableCollection<Student>();
public Mediator Mediator
{ get; set; }
public MainWindow()
{
InitializeComponent();
students.Add(new Student() { ID = "1", FirstName = "Bob", LastName = "Smith", Degree = "Associate" });
students.Add(new Student() { ID = "2", FirstName = "Alex", LastName = "White", Degree = "Certificate" });
students.Add(new Student() { ID = "3", FirstName = "Chris", LastName = "Martin", Degree = "Master" });
students.Add(new Student() { ID = "4", FirstName = "Michal", LastName = "Brown", Degree = "Bachlor" });
Mediator = new Mediator();
Mediator.Register("mymessage1", studentform.Notify);
Mediator.Register("mymessage1", studentlist.Notify);
Mediator.Register("mymessage2", studentform.AnotherNotify);
studentform.Mediator = Mediator;
studentlist.Mediator = Mediator;
DataContext = students;
}
}
}
Just for demonstration purpose we send both “mymessage1” and “mymessage2” messages whenever there is selection change in the CustomizedList user control.
{
SelectedStudent = list.SelectedItem as Student;
Send("mymessage1", SelectedStudent);
Send("mymessage2", SelectedStudent);
}
First Send method call all the methods register for “mymessage1” (studentform.Nofity and studentlist.Nofity) and second Send method call all the methods register for “mymessage2” (studentform.AnotherNofity).
Here is a complete code of our StudentForm user control.
namespace MediatorUserControl
{
/// <summary>
/// Interaction logic for StudentForm.xaml
/// </summary>
public partial class StudentForm : UserControl
{
public Mediator Mediator
{ get; set; }
public StudentForm()
{
InitializeComponent();
}
public void Notify(object message)
{
Student student = message as Student;
if (student != null)
{
DataContext = student;
}
}
public void AnotherNotify(object message)
{
}
}
}
And here is complete C# code of CustomizedList user control.
using System.Windows.Controls;
namespace MediatorUserControl
{
/// <summary>
/// Interaction logic for CustomizedList.xaml
/// </summary>
public partial class CustomizedList : UserControl
{
public static readonly DependencyProperty SelectedStudentProperty =
DependencyProperty.Register("SelectedStudent", typeof(Student), typeof(CustomizedList));
public Student SelectedStudent
{
get { return (Student)GetValue(SelectedStudentProperty); }
set { SetValue(SelectedStudentProperty, value); }
}
public Mediator Mediator
{ get; set; }
public CustomizedList()
{
InitializeComponent();
}
private void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectedStudent = list.SelectedItem as Student;
Send("mymessage1", SelectedStudent);
Send("mymessage2", SelectedStudent);
}
public void Send(string message, object param)
{
Mediator.Send(message, param);
}
public void Notify(object message)
{
}
}
}
The output of this program is same as previous program.

[...] a mediator that can register different type of messages with different type of call back methods here. But there are still two problems in it. The first problem is that we have to pass the object as a [...]
By: Using Mediator to communicate between user controls: Part 5 « Zeeshan Amjad's WPF Blog on January 11, 2012
at 12:08 am