Posted by: Zeeshan Amjad | January 11, 2012

Using Mediator to communicate between user controls: Part 5

We made 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 parameter to the call back method and then do the casting. In other words it is not type safe. The other problem is that once message is registered then there is no way to unregister the message. Let’s handle both problems one by one.

Type safety we can handle by using generics. But there is going to be one change in the internal data structure i.e. dictionary to store call back method. Now we don’t know in advance what will be the parameter of the call back method, therefore we are creating list of Delegate instead of Action<object>. Here is our new dictionary object to store call back methods against messages.

Code Snippet
private Dictionary<string, List<Delegate>> actions =
    new Dictionary<string, List<Delegate>>();

 

Now come to Register method. We make this method generic so we can pass any parameter to Action delegate. Here is modified code of our Register method.

Code Snippet
public void Register<T>(string message, Action<T> action)
{
    if (!actions.ContainsKey(message))
    {
        actions[message] = new List<Delegate>();
    }
    
    actions[message].Add(action);
}

 

Note that we can add the Action<T> type object inside the List<Delegate>. Now we have to specify the parameter type of the delegate at the time of registering the message. Here is a code to register the callback methods.

Code Snippet
Mediator = new Mediator();
Mediator.Register<Student>("mymessage1", studentform.Notify);
Mediator.Register<Student>("mymessage1", studentlist.Notify);
    
Mediator.Register<Student>("mymessage2", studentform.AnotherNotify);

 

Its main advantage is that now we don’t have to do the typecasting inside the call back method, because call back method accept the correct type. Our call back method is quite simple now. Here is a code of our new call back method.

Code Snippet
public void Notify(Student student)
{
    DataContext = student;
}

 

Now let’s come to another problem i.e. unregister the callback method. This code is almost opposite of register method. First check if there is any method register against the given method, then remove it and if the list of call back methods empty then remove that entry from the registry. Here is a code of unregister method.

Code Snippet
public void UnRegister<T>(string message, Action<T> action)
{
    if (actions.ContainsKey(message))
    {
        List<Delegate> actionlist = actions[message];

        actionlist.Remove(action);

        if (actionlist.Count == 0)
            actions.Remove(message);
    }
}

 

Here is the usage of this method.

 

Code Snippet
Mediator.UnRegister<Student>("mymessage1", studentform.Notify);
Mediator.UnRegister<Student>("mymessage1", studentlist.Notify);
Mediator.UnRegister<Student>("mymessage1", studentlist.Notify);

 

Note that even if we register the same call back method more than once, then it has no effect. Here is complete C# code of our new mediator class.

Code Snippet
using System;
using System.Collections.Generic;

namespace MediatorUserControl
{
    public class Mediator
    {
        private Dictionary<string, List<Delegate>> actions =
            new Dictionary<string, List<Delegate>>();

        public Mediator()
        {
        }

        public void Register<T>(string message, Action<T> action)
        {
            if (!actions.ContainsKey(message))
            {
                actions[message] = new List<Delegate>();
            }
            
            actions[message].Add(action);
        }

        public void UnRegister<T>(string message, Action<T> action)
        {
            if (actions.ContainsKey(message))
            {
                List<Delegate> actionlist = actions[message];

                actionlist.Remove(action);

                if (actionlist.Count == 0)
                    actions.Remove(message);
            }
        }

        public void Send<T>(string message, T param)
        {
            if (actions.ContainsKey(message))
            {
                List<Delegate> actionslist = actions[message];

                foreach (var action in actionslist)
                {                    
                    action.DynamicInvoke(param);
                }
            }
        }
    }
}

 

Here is a complete code of our main program.

Code Snippet
using System;
using System.Collections.ObjectModel;
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<Student>("mymessage1", studentform.Notify);
            Mediator.Register<Student>("mymessage1", studentlist.Notify);
                
            studentform.Mediator = Mediator;
            studentlist.Mediator = Mediator;

            DataContext = students;
        }
    }
}

 

Code for both user controls are almost same the only difference is now our call back methods accept the parameter of given type not the object, so we don’t have to down cast it.

Here is a code of CustomizedList user control.

Code Snippet
using System.Windows;
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, Student student)
        {
            Mediator.Send<Student>(message, student);
        }

        public void Notify(Student message)
        {

        }
    }
}

 

And here is C# code of StudentForm user control.

Code Snippet
using System.Windows.Controls;

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(Student student)
        {
            DataContext = student;
        }
    }

    class test
    {
        public int a { get; set; }
    }
}

The output of the program is same as previous programs.

mediator_02_output

Posted by: Zeeshan Amjad | January 9, 2012

Using Mediator to communicate between user controls: Part 4

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.

Code Snippet
private Dictionary<string, List<Action<object>>> actions =
    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.

Code Snippet
public void Register(string message, Action<object> action)
{
    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.

Code Snippet
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);
        }
    }
}

 

Here is complete code of our modified Mediator class.

Code Snippet
using System;
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.

Code Snippet
Mediator = new Mediator();
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.

Code Snippet
using System.Collections.ObjectModel;
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.

Code Snippet
private void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    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.

Code Snippet
using System.Windows.Controls;

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.

Code Snippet
using System.Windows;
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.

mediator_02_output

Posted by: Zeeshan Amjad | January 8, 2012

Using Mediator to communicate between user controls: Part 3

In previous two parts we saw two different implementations of mediator design pattern here and here. Although in second part we remove the dependencies of specific user control from the mediator class and make it flexible enough to register as many client as you want using Register method. But we actually introduced one dependency for all the client. Now all of our client has to implement IMediatorClient interface.

Let’s take one step further and try to remove that dependency too. We change our mediator class little bit and instead of registering the mediator client, now we are going to register the call back method of every client. Our register method accept Action<object> type that is actually a callback method. And in send method we call all the method using DynamicInvoke method of Delegate class to call the callback method. Here is updated version of our mediator class.

Code Snippet
using System;
using System.Collections.Generic;

namespace MediatorUserControl
{
    public class Mediator
    {
        private List<Action<object>> actions = new List<Action<object>>();

        public Mediator()
        {
        }

        public void Register( Action<object> action)
        {
            actions.Add(action);
        }

        public void Send(object message)
        {
            foreach (var action in actions)
            {
                action.DynamicInvoke(message);
            }
        }
    }
}

 

Now we no more need to implement IMediatorClient interfaceSSSDFR55556 for our user controls. In our main window, we are registering the call back methods. Here is a piece of code to use the mediator.

Code Snippet
Mediator = new Mediator();
Mediator.Register(studentform.Notify);
Mediator.Register(studentlist.Notify);

studentform.Mediator = Mediator;
studentlist.Mediator = Mediator;

 

Here is a complete code of our main window.

Code Snippet
using System.Collections.ObjectModel;
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(studentform.Notify);
            Mediator.Register(studentlist.Notify);

            studentform.Mediator = Mediator;
            studentlist.Mediator = Mediator;

            DataContext = students;
        }
    }
}

 

The code for both user controls are exactly same, the only difference is that now we are no more implementing the IMediatorClient interface and we even don’t need that interface in our project.

Here is a code for CustomizedList user control.

Code Snippet
using System.Windows;
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(SelectedStudent);
        }

        public void Send(object message)
        {
            Mediator.Send(message);
        }

        public void Notify(object message)
        {

        }
    }
}

 

And here is a code of user control of StudentForm user control.

Code Snippet
using System.Windows.Controls;

namespace MediatorUserControl
{
    /// <summary>
    /// Interaction logic for StudentForm.xaml
    /// </summary>
    public partial class StudentForm : UserControl
    {
        public Mediator Mediator
        { get; set; }

        public StudentForm()
        {
            InitializeComponent();
        }

        public void Send(object message)
        {
        
        }

        public void Notify(object message)
        {
            Student student = message as Student;

            if (student != null)
            {
                DataContext = student;
            }
        }
    }
}

The output of this program is exactly same as previous program.

mediator_02_output

Posted by: Zeeshan Amjad | January 6, 2012

Using Mediator to communicate between user controls: Part 2

We saw our first cut and very naïve example of mediator here. Although it works in that example but there are several limitations in it. The biggest problem is that mediator is not reusable. Mediator contains the very hard references of two user controls so we can’t use it in any other project, even in the same project to communicate with two other user control. In that case we might end up using more than one mediator class. Not only this we are still limited to only two user control per mediator. Using the existing mediator we can’t communicate with more than two user controls at a time.

Lets first remove the dependency of any specific user control from the mediator class. We introduced one simple interface in the project. The purpose of this interface is to make a collection of classes implement that interface in the mediator. As a added bonus now we can add as many user control inside the mediator as we want. Here is a code of our interface.

Code Snippet
public interface IMediatorClient
{
    void Send(object message);

    void Notify(object message);
}

 

Here is a class diagram of it.

IMediatorClient

Now our mediator class is very simple and not specific to any user control. Here is a code of our modified mediator.

Code Snippet
public class Mediator
{
    private List<IMediatorClient> clients = new List<IMediatorClient>();

    public Mediator()
    {
    }

    public void Register(IMediatorClient client)
    {
        clients.Add(client);
    }

    public void Send(object message)
    {
        foreach (var client in clients)
        {
            client.Notify(message);
        }
    }
}

 

Note that we are no more accepting the user control in constructor of the mediator. But we introduced a Register method and the whole purpose of the register method is to create a list of all classes that implement IMediatorClient interface.

Send function is very simple. We just iterate through all the register classes and call Notify method of every class.

We have to change the code of main window class little bit. In our main window class, now we are registering the user control one by one. It is important that no matter how many user control do we have, message will be send to only those classes which are register in the mediator. Here is a complete code of our main window.

Code Snippet
using System.Collections.ObjectModel;
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(studentform);
            Mediator.Register(studentlist);

            studentform.Mediator = Mediator;
            studentlist.Mediator = Mediator;

            DataContext = students;
        }
    }
}

 

Now the last missing part is to implement the IMediatorClient interface to both user control. This step is quite straight forward, because we already have Send and Notify method implemented in these controls. Here is a complete code for CustomizedList user control.

Code Snippet
using System.Windows;
using System.Windows.Controls;

namespace MediatorUserControl
{
    /// <summary>
    /// Interaction logic for CustomizedList.xaml
    /// </summary>
    public partial class CustomizedList : UserControl, IMediatorClient
    {
        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(SelectedStudent);
        }

        public void Send(object message)
        {
            Mediator.Send(message);
        }

        public void Notify(object message)
        {

        }
    }
}

 

And here is complete code of StudentForm user control.

Code Snippet
using System.Windows.Controls;

namespace MediatorUserControl
{
    /// <summary>
    /// Interaction logic for StudentForm.xaml
    /// </summary>
    public partial class StudentForm : UserControl, IMediatorClient
    {
        public Mediator Mediator
        { get; set; }

        public StudentForm()
        {
            InitializeComponent();
        }

        public void Send(object message)
        {
        
        }

        public void Notify(object message)
        {
            Student student = message as Student;

            if (student != null)
            {
                DataContext = student;
            }
        }
    }
}

 

This relationship can be shown by this diagram.

mediator_02

The output and functionality of this program is exactly same as previous program. But this program has one advantage that now we can reuse the mediator class in any other project and can use with more than two user controls. Here is a the output of the program.

mediator_02_output

Posted by: Zeeshan Amjad | January 5, 2012

Using Mediator to communicate between user controls: Part 1

We saw one example of user control with dependency property here. Now we are going to introduce one more  user control and see how they communicate with each other using mediator design pattern. This is a first and naïve approach of mediator pattern that I am planning to improve in future.

Let’s first take a look at user control. Our first user control is a customized list. This control is very much similar to the control defined in this post. The only different is it display the student information in the list box and display the selected student first name at the top. Here is our student class.

Code Snippet
public class Student
{
    public string ID
    { get; set; }

    public string FirstName
    { get; set; }

    public string LastName
    { get; set; }

    public string Degree
    { get; set; }
}

 

Here is a XAML of our customized list box user control.

Code Snippet
<UserControl x:Class="MediatorUserControl.CustomizedList"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <DockPanel>
        <Border DockPanel.Dock="Top" Margin="5"
                BorderThickness="2" BorderBrush="Black" CornerRadius="5">
            <TextBlock Margin="3" Foreground="Blue"
                       Text="{Binding ElementName=list, Path=SelectedItem.FirstName}">
            </TextBlock>
        </Border>
        <ListBox Margin="5" ItemsSource="{Binding}" x:Name="list"
                 HorizontalContentAlignment="Stretch" SelectionChanged="list_SelectionChanged">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="3" >
                        <TextBlock Text="{Binding ID}"/>
                        <TextBlock Text="{Binding FirstName}"/>
                        <TextBlock Text="{Binding LastName}"/>
                        <TextBlock Text="{Binding Degree}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </DockPanel>
</UserControl>

 

Note we handle the SelectionChange event here to update the dependency property of currently selected student. Here is C# code of our user control.

Code Snippet
using System.Windows;
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 CustomizedList()
        {
            InitializeComponent();
        }

        private void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            SelectedStudent = list.SelectedItem as Student;
        }
    }
}

In a same way we created a user control to display the record of individual student. Here is XAML code for our Student form user control.

Code Snippet
<UserControl x:Class="MediatorUserControl.StudentForm"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Column="0" Grid.Row="0" VerticalAlignment="Center" Margin="5" Text="ID"/>
        <TextBox Grid.Column="1" Grid.Row="0" VerticalAlignment="Center" Margin="5" Text="{Binding ID}"/>
        <TextBlock Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" Margin="5" Text="FirstName"/>
        <TextBox Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" Margin="5" Text="{Binding FirstName}"/>
        <TextBlock Grid.Column="0" Grid.Row="2" VerticalAlignment="Center" Margin="5" Text="LastName"/>
        <TextBox Grid.Column="1" Grid.Row="2" VerticalAlignment="Center" Margin="5" Text="{Binding LastName}"/>
        <TextBlock Grid.Column="0" Grid.Row="3" VerticalAlignment="Center" Margin="5" Text="Degree"/>
            <TextBox Grid.Column="1" Grid.Row="3" VerticalAlignment="Center" Margin="5" Text="{Binding Degree}"/>
    </Grid>
</UserControl>

 

There is nothing special in the C# code of this user control. We put both of our control in the main window. Here is a XAML code of our main window.

Code Snippet
<Window x:Class="MediatorUserControl.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MediatorUserControl"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <local:CustomizedList x:Name="studentlist" Grid.Column="0" Margin="5"/>
        <local:StudentForm x:Name="studentform" Grid.Column="1" Margin="5"/>
    </Grid>
</Window>

 

And we simply create an object of ObservableCollection class of Student type and assign it to the DataContext property of the main window. Now if we run the application then it display all the student in the listbox and display the detail of first student in the collection in the student form user control.

Now even if I select any other student in the student list user control that changes in not going to reflect in student form user control, because there is no communication between these two controls.

One solution is to introduce one dependency property in student form user control too and then do the user control to user control binding using ElementName property of the binding class. In this simple example that may be a good solution. But what will the situation if there are lots of  user control and they are trying to communicate with each other?

Mediator design patter is a good solution here. Mediator design pattern introduced a middle layer and every component is suppose to communicate with it. It is just like a control tower of the airport. During the landing or take off all the airplane are suppose to communicate with control tower, not with each other.

Now let’s make a very basic implementation of mediator. In our example we are concern with two user control so for simplicity we uses the references of both user control in our mediator class. The purpose of mediator in this case is very simple. Whenever get the Send message from anywhere, then notify both user controls.

Here is a simple implementation of Mediator class.

Code Snippet
namespace MediatorUserControl
{
    public class Mediator
    {
        private StudentForm form;
        private CustomizedList list;

        public Mediator(StudentForm form, CustomizedList list)
        {
            this.form = form;
            this.list = list;
        }

        public void Send(object message)
        {
            form.Notify(message);
            list.Notify(message);
        }
    }
}

 

Our next step is to introduce the mediator property in both user control. Now our mediator has a reference of both user controls and user control has reference of mediator class. In this way user control communicate with each other user mediator.

Here is a code of our main class to demonstrate this.

Code Snippet
using System.Collections.ObjectModel;
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(studentform, studentlist);
            studentform.Mediator = Mediator;
            studentlist.Mediator = Mediator;

            DataContext = students;
        }
    }
}

 

This relationship can be shown by this simple diagram.

 

Mediator_01

 

From the CustomizedList user control we are sending the message to the mediator. Here we send the selected student to the mediator. Here is a code for this.

Code Snippet
private void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    SelectedStudent = list.SelectedItem as Student;
    Send(SelectedStudent);
}

public void Send(object message)
{
    Mediator.Send(message);
}

 

On the other hand we handle the message in StudentForm user control. Here is a code to handle the message.

Code Snippet
public void Notify(object message)
{
    Student student = message as Student;

    if (student != null)
    {
        DataContext = student;
    }
}

 

Now we set the data context of the user control to the selected student.

Here is complete code of customized list user control

Code Snippet
using System.Windows;
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(SelectedStudent);
        }

        public void Send(object message)
        {
            Mediator.Send(message);
        }

        public void Notify(object message)
        {

        }
    }
}

 

Here is complete C# code of the student form user control.

Code Snippet
using System.Windows.Controls;

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;
            }
        }
    }
}

 

Here is the output of the program

Mediator_01_Output

Posted by: Zeeshan Amjad | December 30, 2011

Dependency property in User Control

I came across a situation where I am suppose to use two user controls to display the collection and their detail information using MVVM. Let’s make things simple and first try to use it without MVVM. For simplicity we are going to use only one user control and do not use MVVM.

Let’s make a user control first. This user control is a combination of list box and one text box at the top of list box to display the selected item in the list box.  Here is XAML for our user control.

Code Snippet
<UserControl x:Class="WpfUserControlList.CustomizedList"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <DockPanel>
        <TextBlock Margin="5" DockPanel.Dock="Top" Foreground="Yellow" FontSize="24"
                   Text="{Binding ElementName=list, Path=SelectedItem}">
            <TextBlock.Background>
                <LinearGradientBrush>
                    <GradientStop Offset="0" Color="Brown"/>
                    <GradientStop Offset="0.5" Color="LightYellow"/>
                    <GradientStop Offset="1" Color="Brown"/>
                </LinearGradientBrush>
            </TextBlock.Background>
               </TextBlock>
        <ListBox ItemsSource="{Binding}" x:Name="list" HorizontalContentAlignment="Stretch">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border Margin="2" BorderThickness="2" CornerRadius="3" BorderBrush="Brown">
                        <TextBlock Text="{Binding}" Margin="1">
                            <TextBlock.Background>
                                <LinearGradientBrush>
                                    <GradientStop Offset="0" Color="AliceBlue"/>
                                    <GradientStop Offset="1" Color="Blue"/>
                                </LinearGradientBrush>
                            </TextBlock.Background>
                        </TextBlock>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </DockPanel>
</UserControl>

 

Now let’s use our user control in our main program. Here is a XAML to use the user control in our main program.

Code Snippet
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <local:CustomizedList x:Name="uc" Margin="5" Grid.Column="0" DataContext="{Binding}" />
    <TextBlock Margin="5" Grid.Column="1"/>
</Grid>

 

Now if we want to display the selected item in the list box in the main text box, we can’t do it easily right now. One possible solution, if we are using MVVM, is to create one property and assign the selected item to it. Although that approach works but it is not a good design. The reason is that if we want to use this user control in any other project, then we have to do the same thing again and again. The better approach is to introduce one dependency property in the user control.

Here is a code to introduced a dependency property named SelectedItem in our user control. We set this property in the SelectionChanged event of the list box. Here is complete C# code of the program.

Code Snippet
using System.Windows;
using System.Windows.Controls;

namespace WpfUserControlList
{
    /// <summary>
    /// Interaction logic for CustomizedList.xaml
    /// </summary>
    public partial class CustomizedList : UserControl
    {
        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register("SelectedItem", typeof(string), typeof(CustomizedList));

        public string SelectedItem
        {
            get { return (string)GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }

        public CustomizedList()
        {
            InitializeComponent();
        }

        private void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            SelectedItem = list.SelectedItem as string;
        }
    }
}

 

Here is complete XAML code of our user control.

Code Snippet
<UserControl x:Class="WpfUserControlList.CustomizedList"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <DockPanel>
        <TextBlock Margin="5" DockPanel.Dock="Top" Foreground="Yellow" FontSize="24"
                   Text="{Binding ElementName=list, Path=SelectedItem}">
            <TextBlock.Background>
                <LinearGradientBrush>
                    <GradientStop Offset="0" Color="Brown"/>
                    <GradientStop Offset="0.5" Color="LightYellow"/>
                    <GradientStop Offset="1" Color="Brown"/>
                </LinearGradientBrush>
            </TextBlock.Background>
               </TextBlock>
        <ListBox ItemsSource="{Binding}" x:Name="list" HorizontalContentAlignment="Stretch" SelectionChanged="list_SelectionChanged">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border Margin="2" BorderThickness="2" CornerRadius="3" BorderBrush="Brown">
                        <TextBlock Text="{Binding}" Margin="1">
                            <TextBlock.Background>
                                <LinearGradientBrush>
                                    <GradientStop Offset="0" Color="AliceBlue"/>
                                    <GradientStop Offset="1" Color="Blue"/>
                                </LinearGradientBrush>
                            </TextBlock.Background>
                        </TextBlock>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </DockPanel>
</UserControl>

 

Now it we can easily do binding of the selected item of our user control with text box. Here is our XAML to do the binding.

Code Snippet
<TextBlock Margin="5" Grid.Column="1" Text="{Binding ElementName=uc, Path=SelectedItem}" />

 

Here is complete XAML code of our program.

Code Snippet
<Window x:Class="WpfUserControlList.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfUserControlList"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <local:CustomizedList x:Name="uc" Margin="5" Grid.Column="0" DataContext="{Binding}" />
        <TextBlock Margin="5" Grid.Column="1" Text="{Binding ElementName=uc, Path=SelectedItem}" />
    </Grid>
</Window>

 

And here is complete C# code of the program.

Code Snippet
using System.Collections.ObjectModel;
using System.Windows;

namespace WpfUserControlList
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private ObservableCollection<string> states = new ObservableCollection<string>();

        public MainWindow()
        {
            InitializeComponent();

            states.Add("Maryland");
            states.Add("California");
            states.Add("Washington");
            states.Add("Virginia");
            states.Add("Florida");

            DataContext = states;
        }
    }
}

 

This is the output of the program.

UserControlList

Posted by: Zeeshan Amjad | December 23, 2011

Defining and use style using C# in ListBox

I came across a question that how can we change the background color of items in the list box. This is very straight forward task and can be done easily with style using XAML. Here is a simple XAML code to define the style for ListBoxItem.

Code Snippet
<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="Background" Value="AliceBlue"/>
    <Setter Property="FontSize" Value="20"/>
    <Setter Property="Margin" Value="2"/>
</Style>

 

But the next question was how can we define and use it using C# code. Here is a simple C# code to define.

Code Snippet
Style myStyle = new Style(typeof(ListBoxItem));

myStyle.Setters.Add(new Setter(ListBoxItem.BackgroundProperty, Brushes.AliceBlue));
myStyle.Setters.Add(new Setter(ListBoxItem.FontSizeProperty, 20.0));
myStyle.Setters.Add(new Setter(ListBoxItem.MarginProperty, new Thickness(2.0)));

 

We shouldn’t assign the object of Style class to ListBox style property, because the style is ListBoxItem type (we define target type of style as ListBoxItem). Instead we used to set this to ItemContainerStyle property.

Here is a complete C# code of the program.

Code Snippet
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace WpfStyle
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private ObservableCollection<string> states = new ObservableCollection<string>();

        public Window1()
        {
            InitializeComponent();

            states.Add("Maryland");
            states.Add("California");
            states.Add("Virginia");
            states.Add("Washington");

            DataContext = states;

            Style myStyle = new Style(typeof(ListBoxItem));

            myStyle.Setters.Add(new Setter(ListBoxItem.BackgroundProperty, Brushes.AliceBlue));
            myStyle.Setters.Add(new Setter(ListBoxItem.FontSizeProperty, 20.0));
            myStyle.Setters.Add(new Setter(ListBoxItem.MarginProperty, new Thickness(2.0)));

            list.ItemContainerStyle = myStyle;
        }
    }
}

 

And here is our XAML code.

Code Snippet
<Window x:Class="WpfStyle.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Style" Height="300" Width="300">
    <Grid>
        <ListBox Name="list" Margin="5" ItemsSource="{Binding}"/>
    </Grid>
</Window>

 

Here is an output of the program.

ListBoxItemStyle

If we apply different styles with code and XAML at the same time, then the C# code will get precedence and we will see the style defined in C# code not in XAML.

Posted by: Zeeshan Amjad | December 16, 2011

One more Visual Studio designer tip

We saw one small Visual Studio designer tip here. Now we are going to see one more tip. We studied few example of Value converter. Lets take a look at one example of IMultiValueConverter we discuss here. Here is our code.

Code Snippet
#region IMultiValueConverter

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
    string firstName = values[0] as string;
    string lastName = values[1] as string;

    return string.Format("{0}, {1}", lastName, firstName);
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
    throw new NotImplementedException();
}

#endregion

 

Here we are using as operator to check and cast the value into string type. We can directly cast it into string too, because we already know that the value is string. Here is our alternate code.

Code Snippet
#region IMultiValueConverter

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
    string firstName = (string)values[0];
    string lastName = (string)values[1];

    return string.Format("{0}, {1}", lastName, firstName);
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
    throw new NotImplementedException();
}

#endregion

 

And program works exactly the same. Now take a look at the designer. We will get this error at design time.

DesignerError

The reason is that as operator is not throwing an exception if not able to cast into target type. It simply returns null. Therefore it is better to use the as operator and check for null after that while implementing value converter to get an expected design time result.

Posted by: Zeeshan Amjad | December 13, 2011

Value Converter and Markup Extension

We saw an example of Multivalue converter markup extension here. Here we created a class inherited by MarkupExtension base class and implement IMultiValueConverter interface. In fact we can go one step ahead and implement both IValueConverter and IMultiValueConverter in our class so it can be used with Binding as well as Multi Binding. Here is our class.

Code Snippet
[ValueConversion(typeof(String), typeof(String))]
public class StudentNameExtension : MarkupExtension,
    IMultiValueConverter,
    IValueConverter
{
    public StudentNameExtension()
    {

    }

    #region MarkupExtension
    
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    #endregion

    #region IMultiValueConverter

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        string firstName = values[0] as string;
        string lastName = values[1] as string;

        return string.Format("{0}, {1}", lastName, firstName);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion

    #region IValueConverter
    
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Student student = value as Student;

        if (student != null)
        {
            return string.Format("{0}, {1}", student.LastName, student.FirstName);
        }
        else
        {
            return string.Empty;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

 

The usage of this class is also very simple. Here is the usage of both converter in binding and multi binding.

Code Snippet
<TextBlock Margin="5">
    <TextBlock.Text>
        <MultiBinding Converter="{local:StudentName}">
            <Binding Path="FirstName"/>
            <Binding Path="LastName"/>
                            </MultiBinding>
    </TextBlock.Text>
</TextBlock>
<TextBlock Margin="5" Text="{Binding Converter={local:StudentName}}" />

 

Here is complete C# code of the program.

Code Snippet
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace WpfMultiValue
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Student student = new Student() { FirstName = "Bob", LastName = "Smith" };

            DataContext = student;
        }
    }

    public class Student
    {
        public string FirstName
        { get; set; }

        public string LastName
        { get; set; }
    }
    
    [ValueConversion(typeof(String), typeof(String))]
    public class StudentNameExtension : MarkupExtension,
        IMultiValueConverter,
        IValueConverter
    {
        public StudentNameExtension()
        {

        }

        #region MarkupExtension
        
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }

        #endregion

        #region IMultiValueConverter

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            string firstName = values[0] as string;
            string lastName = values[1] as string;

            return string.Format("{0}, {1}", lastName, firstName);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IValueConverter
        
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Student student = value as Student;

            if (student != null)
            {
                return string.Format("{0}, {1}", student.LastName, student.FirstName);
            }
            else
            {
                return string.Empty;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}

 

And here is complete XAML code of the program.

Code Snippet
<Window x:Class="WpfMultiValue.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfMultiValue"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TextBlock Margin="5">
            <TextBlock.Text>
                <MultiBinding Converter="{local:StudentName}">
                    <Binding Path="FirstName"/>
                    <Binding Path="LastName"/>
                                    </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
        <TextBlock Margin="5" Text="{Binding Converter={local:StudentName}}" />
    </StackPanel>
</Window>

 

Here is the output of the program.

BindingMultiBinding

Posted by: Zeeshan Amjad | December 12, 2011

Multi value converter and Markup extension

I came across a question that I have a class with two properties, such as FirstName and LastName, but I want to display the value of these in one control such as TextBlock, how can I do this. In fact there are more than one way to do this. The simplest solution is to do a multi binding and implement IMultiValueConverter nterface. Here is a simple implementation of our interface.

Code Snippet
[ValueConversion(typeof(String), typeof(String))]
public class MultiValue : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        string firstName = values[0] as string;
        string lastName = values[1] as string;

        return string.Format("{0}, {1}", lastName, firstName);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

 

We create an object of it in window resource.

Code Snippet
<local:MultiValue x:Key="multiValue"/>

 

And here is the usage of it.

Code Snippet
<TextBlock Margin="5">
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource multiValue}">
            <Binding Path="FirstName"/>
            <Binding Path="LastName"/>
                            </MultiBinding>
    </TextBlock.Text>
</TextBlock>

But like lots of other WPF thing, here we can do it in more than one way. We can create a markup extension which implement the IMultiValueConverter interface. We already saw few examples of markup extension which implement IValueConverter here and here.

Here is a markup extension to implement IValueConverter.

Code Snippet
[ValueConversion(typeof(String), typeof(String))]
public class MultiValueExtension : MarkupExtension, IMultiValueConverter
{
    public MultiValueExtension()
    {

    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        string firstName = values[0] as string;
        string lastName = values[1] as string;

        return string.Format("{0}, {1}", lastName, firstName);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

 

Here is a usage of this markup extension.

Code Snippet
<TextBlock Margin="5">
    <TextBlock.Text>
        <MultiBinding Converter="{local:MultiValue}">
            <Binding Path="FirstName"/>
            <Binding Path="LastName"/>
                            </MultiBinding>
    </TextBlock.Text>
</TextBlock>

 

Here is a complete C# code of our program.

Code Snippet
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace WpfMultiValue
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Student student = new Student() { FirstName = "Bob", LastName = "Smith" };

            DataContext = student;
        }
    }

    public class Student
    {
        public string FirstName
        { get; set; }

        public string LastName
        { get; set; }
    }
    
    [ValueConversion(typeof(String), typeof(String))]
    public class MultiValueExtension : MarkupExtension, IMultiValueConverter
    {
        public MultiValueExtension()
        {

        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            string firstName = values[0] as string;
            string lastName = values[1] as string;

            return string.Format("{0}, {1}", lastName, firstName);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

 

And here is complete XAML code of the program.

Code Snippet
<Window x:Class="WpfMultiValue.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfMultiValue"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock Margin="5">
            <TextBlock.Text>
                <MultiBinding Converter="{local:MultiValue}">
                    <Binding Path="FirstName"/>
                    <Binding Path="LastName"/>
                                    </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </Grid>
</Window>

 

MultiValueConverterMarkupExtension

Older Posts »

Categories

Follow

Get every new post delivered to your Inbox.

Join 446 other followers