Posted by: Zeeshan Amjad | April 5, 2011

Introduction to RoutedEvent


RoutedEvent are new concept in WPF. This is a class inherited by Object class which define four properties and one method. Here is a class diagram of RoutedEvent class.

RoutedEvent

 

To see the behavior of routed event, we are going to create couple of classes and then see the rouging behavior of it. Here we are going to do all the work in C# code to better understand it and write only minimal code for our purpose. Here is our starting point. We are going to create three classes (to see the routing behavior) and those are inherited by Label, Frame and Window class respectively.

Code Snippet
public class MyLabel : Label
{
    // other stuff
}

public class MyFrame : Frame
{
    // other stuff
}

public class MyWindows : Window
{
    // other stuff
}

 

In next step we are going to define the label as a content of frame and frame as a content of window. Here is a code of it.

Code Snippet
public class MyLabel : Label
{
    // other stuff
}

public class MyFrame : Frame
{
    public MyLabel label = new MyLabel();

    public MyFrame()
    {
        Content = label;
    }

    // other stuff
}

public class MyWindows : Window
{
    private MyFrame frame = new MyFrame();

    public MyWindows()
    {
        Content = frame;
    }

    // other stuff
}

 

This is C# way to define the relationship (making logical tree) among different UIElements.

Now we are going to define our own routed event. We register a routed event using EventManager class. Here is a class diagram of EventManager class.

EventManager

Here is a code to define our own routed event.

Code Snippet
public class MyLabel : Label
{
    public static readonly RoutedEvent myRoutedEvent =
        EventManager.RegisterRoutedEvent("MyEvent", RoutingStrategy.Bubble,
        typeof(RoutedEventHandler), typeof(MyLabel));

    public event RoutedEventHandler MyRoutedEvent
    {
        add { AddHandler(myRoutedEvent, value); }
        remove { RemoveHandler(myRoutedEvent, value); }
    }
}

 

Then we attached our event with mouse left button down. Whenever user press the mouse left button on the label, we are going to raise this event. Here is an update of our class now.

Code Snippet
public class MyLabel : Label
{
    public static readonly RoutedEvent myRoutedEvent =
        EventManager.RegisterRoutedEvent("MyEvent", RoutingStrategy.Bubble,
        typeof(RoutedEventHandler), typeof(MyLabel));

    public event RoutedEventHandler MyRoutedEvent
    {
        add { AddHandler(myRoutedEvent, value); }
        remove { RemoveHandler(myRoutedEvent, value); }
    }

    public MyLabel()
    {
        MouseLeftButtonDown += new MouseButtonEventHandler(MyLabel_MouseLeftButtonDown);
    }

    void MyLabel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        RaiseEvent(new RoutedEventArgs(MyLabel.myRoutedEvent, this));
    }
}

 

In this way we have defined the routed event. Now if we want to handle it in Frame or Window class, we just have to call AddHandler method. Remember AddHandler method is define in UIElement class, therefore we can handle this only UIElement or its child classes. And its perfectly make sense, because parent of UIElement is Visual class which doesn’t have event handling. It means we can’t use this method from any child class of Visual. Here is a class diagram of Visual class.

Visual

 

Here is a code to handle this event in frame class.

Code Snippet
public class MyFrame : Frame
{
    public MyLabel label = new MyLabel();

    public MyFrame()
    {
        Content = label;

        AddHandler(MyLabel.myRoutedEvent, new RoutedEventHandler(MyRoutedHandler), true);
    }

    public void MyRoutedHandler(Object sender, RoutedEventArgs args)
    {

    }
}

 

Similarly here is a code to handle the event in Window class.

Code Snippet
public class MyWindows : Window
{
    private MyFrame frame = new MyFrame();

    public MyWindows()
    {
        Content = frame;

        AddHandler(MyLabel.myRoutedEvent, new RoutedEventHandler(MyRoutedHandler), true);
    }

    public void MyRoutedHandler(Object sender, RoutedEventArgs args)
    {

    }
}

 

Note that the last parameter of AddHandler method is true in both classes. It simply means that even if we marked event as handled (se the Handled property of arguments to true), but we can still handle event here. if we set this to false then we can’t get event as soon as one handler set this property to false.

Here is a complete program to demonstrate this concept. Just to give some output we also created one string type property Message and display its value in message box in MyWindow class handler.

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

namespace Event
{
    public class MyLabel : Label
    {
        public static readonly RoutedEvent myRoutedEvent =
            EventManager.RegisterRoutedEvent("MyEvent", RoutingStrategy.Bubble,
            typeof(RoutedEventHandler), typeof(MyLabel));

        public event RoutedEventHandler MyRoutedEvent
        {
            add { AddHandler(myRoutedEvent, value);  }
            remove { RemoveHandler(myRoutedEvent, value); }
        }

        public String Message
        { get; set; }

        public MyLabel()
        {
            Message = "";

            MouseLeftButtonDown += new MouseButtonEventHandler(MyLabel_MouseLeftButtonDown);

            MyRoutedEvent += new RoutedEventHandler(MyRoutedHandler);
        }

        void MyLabel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            RaiseEvent(new RoutedEventArgs(MyLabel.myRoutedEvent, this));
        }

        public void MyRoutedHandler(Object sender, RoutedEventArgs args)
        {
            Message = "MyLabel.MyRoutedHandler\n";
        }
    }

    public class MyFrame : Frame
    {
        public MyLabel label = new MyLabel();

        public MyFrame()
        {
            Content = label;

            AddHandler(MyLabel.myRoutedEvent, new RoutedEventHandler(MyRoutedHandler), true);
        }

        public void MyRoutedHandler(Object sender, RoutedEventArgs args)
        {
            label.Message += "MyFrame.MyRoutedhandler\n";
        }
    }

    public class MyWindows : Window
    {
        private MyFrame frame = new MyFrame();

        public MyWindows()
        {
            Title = "RoutedEvent";
            Height = 300;
            Width = 400;

            Content = frame;

            AddHandler(MyLabel.myRoutedEvent, new RoutedEventHandler(MyRoutedHandler), true);
        }

        public void MyRoutedHandler(Object sender, RoutedEventArgs args)
        {
            frame.label.Message += "MyWindows.MyRoutedHandler";
            MessageBox.Show(frame.label.Message, args.OriginalSource.ToString());
        }
    }

    public class MyApp
    {
        [STAThread]
        public static void Main()
        {
            MyWindows win = new MyWindows();

            Application app = new Application();
            app.Run(win);
        }
    }
}

 

Here is the message box output when we click on the label.

RoutedEventOutput

Advertisements

Responses

  1. http://www.codeproject.com/KB/architecture/UsingFactoryPattern.aspx

    Typos:

    “From a compiler’s prospective”
    Change to
    “From a compiler’s perspective”

    “in other definition file”
    “in another definition file”

    • Thanks for correction 🙂


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: