Chapter 4. Implementing Application Logic

So far, we have mainly dealt with the UI layer, but no application can be called an application without some logic. In this chapter, we are going to work mainly on the code behind layer of our application. We will discuss the concept of events, dive deep into dependency properties, interact with attached properties, and finish off with the ICommand interface. With so many exciting topics, we'd better get started right away!

In this chapter, we will cover the following topics:

  • Handling events
  • Consuming services asynchronously
  • Working with background threads
  • Working with dependency properties
  • Interacting with attached properties
  • Implementing ICommand

Handling events

If you have ever worked with events in any .NET-based language, you will feel right at home with Silverlight. Just like other .NET languages, you can select an element in the design area, and generate the event handler automatically using Visual Studio 2010. Of course, you are not limited to adding events only in the designer, you can attach events in the code behind as well.

The Silverlight event model is based upon the concept of bubbling events. This means that a control can raise an event that will be handled by its parent control. For example, if we have a Border control that has a StackPanel with images as its content, we can handle the MouseLeftButtonDown event on the border level, instead of having to handle it for each individual image. Bubbling is a type of routed events and the only one that Silverlight supports. Bubbling means going up the control hierarchy and while WPF does support the tunneling type of routed event (going down the hierarchy), Silverlight does not.

Note

A handful of events in Silverlight are routed events. For a full list of routed events, have a look at the MSDN documentation at http://msdn.microsoft.com/en-us/library/cc189018(v=vs.95).aspx#routed_events.

Silverlight does not support user-created bubbling events. That means that events you create on your own in Silverlight will never bubble.

Let's get the wheels rolling with understanding how to add events in Silverlight.

Adding events

As mentioned previously, we can add events on both the UI (XAML) layer and code behind. Adding events with XAML is as easy as typing the event and specifying its handler. For example, the following line of code demonstrates how to declare a Click handler for a button using XAML:

<Button x:Name="myBtn" Content="Click me!" Click="myBtn_Click"/>

By specifying the Click method in XAML, Visual Studio creates the event handler (myBtn_Click) in the code behind of the page. If you take a look in the code behind file, you will see the following method:

private void myBtn_Click(object sender, RoutedEventArgs e)
{
}

The other option of adding an event is purely on the code behind file. To attach an event handler for the Click event of a button, we can use the following line of code:

myBtn.Click += new RoutedEventHandler(myBtn_Click);

This will also get Visual Studio to create the event handler for us, in this case the event handler will be myBtn_Click, as specified in the declaration code.

Now that we know the basics of adding events in Silverlight, let's go ahead and understand the concept of routed events.

Handling routed events

As we have discussed earlier, when using routed events, the control that raised the event isn't necessarily the one that handles it. This means that the bubbling begins with the control that raised the event and stops when a control, somewhere up the hierarchy handles the event, or when it reaches the top-level control.

Control-specific events, for example the Click event for a Button control, will never be routed. If you think about that, it's pretty logical too—why make an event bubble up the control hierarchy if it can only be handled by a specific type of control?

To demonstrate routed events, create a new Silverlight project in Visual Studio 2010 and name it Chapter4-HandleEvents.

Open MainPage.xaml and replace your LayoutRoot Grid element with the following code snippet:

<Grid x:Name="LayoutRoot" Background="White" MouseLeftButtonUp="LayoutRoot_MouseLeftButtonUp">
<Border x:Name="myBorder" Background="Aqua" Margin="20" MouseLeftButtonUp="myBorder_MouseLeftButtonUp">
<StackPanel Background="Red" x:Name="myStackPanel" Margin="20" MouseLeftButtonUp="myStackPanel_MouseLeftButtonUp">
<Rectangle Margin="20" Height="180" x:Name="myRectangle" Fill="DarkSalmon" MouseLeftButtonUp="myRectangle_MouseLeftButtonUp"/>
</StackPanel>
</Border>
</Grid>

What we have here is a hierarchy of controls, starting with the top-level Grid. Inside Grid, we have a Border child element, which in turn holds a StackPanel child element, which in turn holds a Rectangle child element. Each element has a MouseLeftButtonUp event attached to it. Before we can run the application, we have to handle these events, so switch over to your MainPage.xaml.cs file and add the following code snippet:

private void LayoutRoot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
results += "LayoutRoot handled the event";
MessageBox.Show(results);
results = "";
}
private void myBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
results += "myBorder handled the event
";
}
private void myStackPanel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
results += "myStackPanel handled the event
";
}
private void myRectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
results += "myRectangle handled the event
";
}

Add the following private variable just above the MainPage constructor declaration:

private string results = "";

To recap, we have added all the event handlers for the events we declared in the UI layer. Each handler will add its name to the private string variable, and the LayoutRoot event handler will pop up a message box to the user with the content of the results variable.

Go ahead and build your application. Run it and you should get the following result:

Handling routed events

In the preceding diagram, we can see all of our controls. The white area is the top-level Grid, below it we have our Border, then StackPanel, and finally the salmon-colored Rectangle. Click on the Rectangle element and you should get the result, as shown in the following screenshot:

Handling routed events

As you can see, the MouseLeftButtonUp event has bubbled up all the way to the LayoutRoot control, which handled it. We know it was the LayoutRoot event handler that finally handled it because it was the only event that popped out a message box for us. Click on any of the other controls and you will see that the event will always bubble up to the top-level control of the hierarchy.

Now you may ask yourself what if we wanted to stop the bubbling at the Border control?

The answer to that is very easy—we set the Handled property of the desired event handler's MouseButtonEventArgs to true!

Switch back to your MainPage.xaml.cs file and locate the myBorder_MouseLeftButtonUp event handler. Add the following line of code at the end of the method:

e.Handled = true;

Build and run your application, and you should notice that the pop-up message doesn't show up unless you click directly on the Grid control area (the white background). By setting the Handled property, we have successfully told Silverlight that the event was handled and there is no need for it to keep bubbling up.

The AddHandler method

The AddHandler method allows you to add a routed event handler for a specific routed event in the code behind layer. It also provides you with the option to always invoke the specified handler, even if the routed event was already marked as handled by another element along the control hierarchy. To demonstrate the AddHandler method, let's remove the MouseLeftButtonUp event from the LayoutRoot control's XAML declaration. Switch over to your MainPage.xaml.cs file and add the following line of code inside the constructor method:

this.AddHandler(UIElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler(LayoutRoot_MouseLeftButtonUp), true);

The preceding line of code will attach the MouseLeftButtonUp event to the this object, which represents the current active page (MainPage.xaml in our example), using the AddHandler method. We aren't limited to the use of the this object when using the AddHandler method, and we could just as easily attach events using the AddHandler method to any UIElement control in the page (LayoutRoot for example).

The AddHandler method expects to get the following three arguments:

  • The routed event we wish to attach. In our example, we wish to attach the MouseLeftButtonUp event.
  • A reference to the handler method. As we already had the method in the page from the last example, we just pass its name as an argument.
  • A Boolean value that indicates whether or not to handle events that were previously handled by other handlers. As we want to handle the MouseLeftButtonUp event within the page level, and we don't care if the event was already handled, we will pass true as an argument in our example.

In your code behind, add the following line of code to myBorder_MouseLeftButtonUp, myStackPanel_MouseLeftButtonUp, and myRectangle_MouseLeftButtonUp:

e.Handled = true;

By setting the Handled property of the EventArgs object to true, we tell the Silverlight framework that this event is handled and shouldn't bubble up the pipe.

Build and run your application. You should see that even though we haven't registered any event on LayoutRoot directly, and even though we handled the event on all of the controls, we still get the message box to pop up with the text inside of it.

Try removing the event declarations on all of the controls in your XAML file and see what happens. It should come as no surprise to you that the only event handler that gets called is the one we defined within the AddHandler method.

By using the AddHandler method on the page level, we basically register that event for any control in the page, so no matter if the control itself declares an event handler for this method or not, the AddHandler registered routed event will get called.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.124.21