Thursday, April 1, 2010

Call and Raise Events in WPF from Child Control to parent window

I know there are a lot of documentation on routed events in wpf, and examples. For example see http://www.codeproject.com/KB/WPF/BeginWPF3.aspx

Either way, for some reason I just wasn't getting it. It took a couple of hours of reading and trying, but I was finally able to figure it out. Below is my explanation.

Just say you have a MainWindow and in it you have a custom control, called ControlHome. In your ControlHome you want to raise an event and have it caught by the MainWindow. Back in WinForms you would define the event in the control, raise it in the control and then "catch" it in the MainWindow. The idea is somewhat similar in WPF, but you have to do something called Routed Events, and with Routed Events you can do a lot more, but I'll just focus on the scenario of Child Control to MainWindow.

In the Child Control (called ControlHome) you need to create the event
public static RoutedEvent StartProgressBarEvent;
(I've seen a lot of documentation where it was made read-only, but when I did this, I get an error when I define it in the Constructor so I removed the readonly statement.

In the constructor of the child control you register it like this:

StartProgressBarEvent = EventManager.RegisterRoutedEvent("StartProgressBar", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(ControlHome));

I specified it to "Bubble" which means it goes up the tree. I name "StatusProgressBar" will be used later on. The type is RoutedEventHandler, and ChildControl is the control that is going to raise the event

You also need to add the handler for the Event like this to the child control:
public event RoutedEventHandler StartProgressBar
{
add {base.AddHandler(StartProgressBarEvent, value);}
remove {base.RemoveHandler(StartProgressBarEvent, value);}
}

Lastly when you want to raise the event you can do so like this:
RoutedEventArgs e1 = new RoutedEventArgs(StartProgressBarEvent);
RaiseEvent(e1);

So to review, in the Child Control, you create it, register it and add the handler for it, and raise it when you want to. Now your child control has this event registered to it, so a parent window can just call it. For example, the button has an event called Click, so a parent event can define what will happen when a user clicks on the button.

In the parent window, in the ChildControl.xaml file, where I added the control to the file, I now say that the even StartProgressBar will be handled by the function "StartProgressBar"

<local:ChildControlx:Name="ChildControl1" StartProgressBar="StartProgressBar"/>

In the file ChildControl.xaml.cs, I define the StartProgressBar function, like this:
private void StartProgressBar(object sender, RoutedEventArgs e)
{
// Do something here
}

That's it. The RoutedEvents also allow you to tunnel events down the tree, but I won't get into that right now.

No comments: