Silverlight: User Controls with events

This article is for Silverlight 2 beta 1

Update: Corrado Cavalli translated the example in VB.NET. Thanks Corrado!!

Apparently, one reader had issues declaring events for the User Control example that I posted earlier this week.

He is programming in VB and unfortunately I don't have a lot of experience with VB.NET, so I first created a working example with C#, and my good friend and fellow MVP Corrado Cavalli translated the example in VB.NET (see below).

The big difference between WPF and Silverlight regarding events is that Silverlight doesn't support Routed Events (yet?). To be precise, some events are routed (all input events like MouseLeftButtonDown, KeyDown, etc...

Instead of declaring RoutedEvents in our User Control, we have to resort to standard .NET events then. From a user point of view, it doesn't make a very big difference in the subscribing, but of course these events will not tunnel nor bubble (for a summary of RoutedEvents, bubbling and tunneling in WPF, read this).

The sample here declares a User Control called LeftRightButton, with two buttons, a LeftButton and a RightButton. it also declares two events, a LeftClick and a RightClick. When the RightButton gets clicked, the UserControls catch this event and raises a RightClick event. The same happens with the LeftButton and the LeftClick event.

Declaring new events for any class requires a Handler declaration (a delegate), and then the event declaration itself.

public delegate void ClickHandler(object sender, EventArgs e); public event ClickHandler RightClick; public event ClickHandler LeftClick;

The next step is to catch the internal click events, and to raise the corresponding "external" event. Note that in this simplified example, I just re-route the RoutedEventArg for the event. Often, you need to declare your own class inheriting EventArgs, for example to pass additional parameters to the event subscriber.

So if the XAML LeftButton is declared as:

<Button x:Name="LeftButton" Click="LeftButton_Click" />

then we have:

void RaiseLeftClick(RoutedEventArgs e) { if (LeftClick != null) { LeftClick(this, e); } }

Note how we check if the event is null before we raise it. If no one subscribed to the event, LeftClick will be null, and there is a risk for a NullReferenceException to be thrown.

Then only thing that we need to do now is catch the internal click event, and raise the corresponding RightClick or LeftClick event.

private void LeftButton_Click(object sender, RoutedEventArgs e) { RaiseLeftClick(e); }

The User Control raising these events is located in an external assembly as shown here. I use 4 instances of the User Control in a Silverlight application. This way, we demonstrate how to raise new events, how to catch them in another assembly, and how to handle them.

<controls:LeftRightButton x:Name="ButtonTopLeft" RightClick="LeftRightButtonButton_RightClick" LeftClick="LeftRightButtonButton_LeftClick" />
private void LeftRightButtonButton_LeftClick(object sender, EventArgs e) { LastEventControlNameTextBlock.Text = (sender as LeftRightButton).Name; LastEventEventNameTextBlock.Text = "LeftClick"; }
4 user controls with events

The source code in C# can be downloaded here.

The source code in VB.NET (translated by Corrado Cavalli) can be downloaded here.

http://www.galasoft.ch

Print | posted on Saturday, April 26, 2008 9:59 PM

Feedback

# re: Silverlight: User Controls with events

left by Bruce Chase at 5/21/2008 5:47 AM Gravatar
I have multiple user controls for which I must alert other controls of events that have occurred in another user control. One control in particular uses a socket connection and thus transfers and received streams of information. In transferring and raising events in a user control other than the one for which the socket is connected, I receive threading exceptions. I would like to see your example, but alas, cannot reach the C# page. Thanks in advance.

# re: Silverlight: User Controls with events

left by Laurent at 5/21/2008 11:35 AM Gravatar
Hi Bruce,

I can email you the code if you pass me your email address. However, I think your problems rather comes from the fact that you may not modify a UI element (belonging to the UI thread) from a worked thread directly. You need to dispatch the call to the UI thread using the Dispatcher class.

The problem (and solution) is described in this page:
http://www.ddj.com/windows/207602773

Greetings,
Laurent

# re: Silverlight: User Controls with events

left by Bruce Chase at 5/22/2008 3:54 AM Gravatar
Laurent,

I solved the problems. I had to add delegate handlers for most functions that modify UI elements or that made further calls to the thread for socket communications. I believe that by doing this, the events were put in the que for the single main thread. Thus, the thread was not walking all over itself.

Thanks for the link and all your good work

# re: Silverlight: User Controls with events

left by Laurent at 5/22/2008 10:55 AM Gravatar
Happy to hear you solved the problem. I would take a good look to the Dispatcher class, it is a very critical class to understand as soon as you do multithreading. The good news is that the class also exists in WPF, so if you get it in Silverlight, you will be able to use that knowledge in "big brother" too.

Greetings,
Laurent
Title  
Name
Email (never displayed)
Url
Comments   
Please add 8 and 8 and type the answer here: