Friday, March 30, 2007

Routed Events

Routed Events(This is another intresting concept in WPF)


Raising and handling events with the WPF is based on the new XAML markup structures, and how events are routed through a tree of elements. When a XAML page contains nested controls, there are interactive complexities that never before existed in the typical .NET UI environment.‘Nested’ controls create what is known as a Logical Tree and a Visual Tree.

Application developers have been required in times past to‘Walk-the-Tree’ by raising events and/or calling methods for each logical ‘node’ within a nested hierarchy.Events in the WPF are called Routed because there is a brand new chronological process by which to handle these events. This ordered, or routed, list of events will fire in a controlled fashion, providing full view of event the most complex Visual Trees. With the advent of Routed Events in the WPF.


The complications involved with capturing a series of hierarchical events are encapsulated and simplified. Routed Events are a pipeline of event handlers that are automatically fired for a control when any of its nested controls’ events fire. This means that it performs as a self-aware component, knowing when its members are being interacted with, and providing handler logic to respond to user or system related interactions.


A FrameworkElement could possible contain other sibling and child elements, which forms a tree of elements. In the WPF, the parent element can provide information to child elements, providing usage, customization, and visibility to the potentially smaller, nested objects. "Control Composition" is a term used to describe the creation or design concepts used when creating controls and providing thought to the handling of information within the tree. It leads developers to creating better structure for controls to control and direct the logical flow of events for the tree and its members.


Types of RoutedEvents
  1. Tunneling
  2. Bubbling
  3. Direct
A Bubbling event is the first place we will start, as it provides event handling from the originating element of a Visual Tree to the root of the tree. Tunneling event, on the other hand, fire in the opposite direction and are used to hook into the pre-condition of the controls within the visual tree from the top of the visual tree down. Tunneling and Bubbling event models assist in the complicated logic associated to events raised from / by controls within other controls. Developers can hook into an action before or after it occurs in context to its parent and child controls. Direct Event is typical .Net event handler concept.



Lets we will talk about RoutedEvent in detailed manner.



In WPF application contain many elements. You can see these elements in elements tree.(Such as visual tree). The routed event model enables you to use the element tree . This routed event will route along a route after its raised .It can travel in one of two directions. Event Listeners invoke the handlers from the root element to all successive child elements along the source element , this is called tunneling . And Event Listeners invoke the handlers from the source element to all successive parent elements along the Root element , this is called Bubbling Event.


Syntax For Routed Event

public static readonly RoutedEvent eventNameEvent;

Here event name followed by the word Event(Ex: TaskEvent)

The RoutedEvent instance obtained from registration is retained as a public static readonly field member of the class EventManager.ResgisterRoutedEvent.

Initializing Routed Event.

eventName=EventManager.ResgisterRoutedEvent(“eventName”,RoutingStratagy,typeof(RoutedEventHandler),typeof(YourClass));

Note : Don't contain Event word with eventName(It should be like : Task)

RoutingStratagy


RoutingStratagy.Tunneling
RoutingStratagy.Bubling
RoutingStratagy.Direct

Add and Remove Implementations(Initializing the Actual Event (language-specific))
we should define the actual event (ex : Task) , here the value argument is the event handler.

public event RoutedEventHandler Task
{
add
{
AddHandler(TaskEvent, value);
}

remove
{
RemoveHandler(TaskEvent, value);
}
}


Use Of RoutedEvent

Group of controls together that should all interact. The parent element is a common listener for the routed event, and uses the same event handler whenever any of the controls raises a particular event.

Example :


In this example no need to write event handler for all the buttons , by using RoutedEvent can place a common Event Handler on the Parent of two buttons. (Here in windows).

Attaching and Implementing an Event Handler for a Routed Event


Attaching a handler for a routed event in an application that is created in code is also straightforward. Routed events almost always have background implementations of add and remove logic that allow the handlers to be added by a language-specific event syntaxRouted event handlers can also be attached through a helper method AddHandler.



Example of the helper method


Button b2 = new Button();
b2.Click += new RoutedEventHandler(myEvent);

void myEvent(object sender, RoutedEventArgs e)
{
//Implementaion
}


Sample For Creating Custom RoutedEvent

MyButton.cs

class MyButton :Button
{
public static readonly RoutedEvent TaskEvent = EventManager.RegisterRoutedEvent("Task", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButton));
// Provide CLR accessors for the event
public event RoutedEventHandler Task
{
add { AddHandler(TaskEvent, value); }
remove { RemoveHandler(TaskEvent, value); }
}
// This method raises the Task event
void RaiseTaskEvent()
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(MyButton.TaskEvent);
RaiseEvent(newEventArgs);
}
//Raise the event when the MyButton is clicked
protected override void OnClick()
{
RaiseTaskEvent();
}
}

Window1.xaml.cs

public partial class Window1 : System.Windows.Window
{
public Window1()
{
InitializeComponent();
// Creating Our Own Control for custom Routed Event
MyButton m=new MyButton();
m.Content ="Click Me";
m.Width =200;
m.Height =30;
this.Content = m;
m.Task += new RoutedEventHandler(m_Task);
}
void m_Task(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hai Iam The Routed Event For Your Button");
// dont want to route others
e.Handled = true;
//throw new Exception("The method or operation is not implemented.");
}
}



Note : Here Task event will raise when you click on the mybutton. and it will show message box with message.

Key Points

For events that should be routed events

  • Declare a public static readonly field to hold your RoutedEvent object
  • Declare CLR accessors for these routed events
  • Declare a protected virtual void On( EventArgs e) method for subclasses to use. Call this method from your “class handler” -- EventManager.RegisterClassHandler(typeof(YourComponent), YourClassHandler).
  • Routed events using RoutingStrategy.Tunnel should have names that begin with “Preview”.
  • Many bubbling events don’t have corresponding tunnelling events, but almost all tunnelling events should have corresponding bubbling events.
  • A tunnelling event should be raised before its corresponding bubbling event. If the tunnelling event was marked as handled, the bubbling event should be marked as handled before the event is raised.

Still If You Cant Get, Try with this ....
http://msdn2.microsoft.com/en-us/library/ms742806.aspx
http://blogs.msdn.com/nickkramer/archive/2005/08/15/451641.aspx

Enjoy!!!!!!!!!!!!!

1 comment:

  1. Hi. Nice article. I have a few questions thatI cannot find answers to and I hope you can help.

    I cannot find how to catch a nested (child) event in a custom user control from the main window in a WPF project.

    Goal 1: When a property in TreeAChild1 changes, I want to display the new value in TreeBChild1.
    Goal 2: When a bind a property in TreeAChild1 to a property TreeBChild1.

    I am told the best way is to bubble the event up from the bottom of Tree A to the main window. Then tunnel the event down Tree B.
    I know how to bubble up the event, but I don't know how to catch the event in the MainWindow. I cannot find any good examples.


    MainWindow
    * TreeA
    - TreeAChild1
    * TreeB
    - TreeBChild2

    Each tree element are custom user controls.


    MainWindow.xaml contains 2 controls (TreeA and TreeB)

    Inside TreeA_Child1.xaml.cs I create the property and an event in TreeBChild2. I have the RoutingStrategy set to bubble.

    When a button is clicked, the value of 'TestString' changes, and I raise the event manuly with RaiseEvent.

    To test the event I listen for the TestStringChanged event and then triger the TestString_Changed in TreeA.

    TreeA.xaml:

    controls:TreeA_Child1 x:Name="TreeA_Child1" TestStringChanged="TestSting_Changed"


    TreeA.xaml.cs:

    private void TestSting_Changed(object sender, RoutedEventArgs e)
    {
    TreeA_Child1 child1 = (TreeA_Child1)sender;
    MessageBox.Show("TestString has changed: " + child1.TestString);

    }

    The test works fine.

    QUESTION: How can I catch (subscribe to) the event in TreeA_Child1 from the MainWindow?
    QUESTION: How do I send and catch the tunneling event from MainWindow to TreeB_Child1?
    QUESTION: Is it also possible to bind TreeA_Child1 to TreeB_Child1? If so, how?

    ReplyDelete