Sunday, August 2, 2009

Silverlight 3 -- D'oh! and Woo Hoo!

In July, Microsoft released Silverlight 3. On the one hand, it's good to see the features moving forward at a good pace. On the other hand, we only had 9 months with Silverlight 2. I just thought I was starting to understand how to work with Silverlight 2 effectively, and wham! new version.

The Bad
First, the bad. I was surprised by some of the items that are included in the Silverlight 3 release notes. Fortunately, I read these before installing the bits.

1. Silverlight 2 & Silverlight 3 compatability
Silverlight 2 projects cannot be created with the Silverlight 3 Tools for Visual Studio 2008. To create Silveright 2 projects, uninstall the Silverlight 3 runtime and the Silverlight 3 Tools from Add or Remove Programs and re-install the Silverlight 2 Tools for Visual Studio 2008.
This was a showstopper for me at work. As I've mentioned, I've been developing a Silverlight 2 application at my day job. Due to certain circumstances, I can't upgrade the project to Silverlight 3 (yet). Since I still need to support it in the meantime, I need to keep the Silverlight 2 bits installed on my machine.

There are some blog posts out there with tips on how to switch back and forth between the 2 versions, but it's making things a bit more complicated than I would like. So, the work machine stays on Silverlight 2 (but Silverlight 3 immediately gets installed at home).

2. Design Preview in Visual Studio 2008
Due to performance and rendering issues, the preview window has been disabled in the Silverlight 3 Tools for Visual Studio 2008. The functionality of the XAML editor remains intact, including IntelliSense, error messages, and the ability to drag controls from the Toolbox into the editor. WYSIWYG XAML design can be done by using Expression Blend or Visual Studio 2010.
This limitation is somewhat disappointing to me. I'm a XAML guy. I'm comfortable typing in the design code directly (and IntelliSense works great in Visual Studio). But I did use the preview window to see how things look. Now, I have to have Expression Blend open to check the preview. I wouldn't mind so much if I used Blend more extensively (which I probably should anyway), but right now it seems like a bit of a kludge to have to toggle back and forth.

There are other notes as well, and I would encourage you to read them in full. These are the ones that jumped out at me as being disappointments.

The Good
So, now the good parts. These are just the items that struck me as useful. There are plenty of other new features (such as out-of-browser support and 3-D support that are interesting but not very applicable in my world).

1. WCF Service Support
Silverlight 3 has support for the full WCF stack. This means that we are no longer limited to basicHttpBinding for our WCF services that are consumed by Silverlight. We can use WS* bindings or any of the other bindings.

2. Controls
In addition, there are plenty of new contols available (including a TreeView) and loads of new layout controls. The Silverlight 3 toolbox is starting to look a lot closer to the WPF toolbox (and excels it in a few cases).

3. Improved XAML
New features such as Behaviors and Triggers greatly enhance the ability to define things declaratively in XAML as opposed to having to implement them in code.

Here's my example: One of my first demos on this blog was a WPF application that was written entirely in XAML. It included a visual re-design of buttons and animation that triggered by clicking the button. It was fully functional with absolutely no code-behind. You can see that entry here: WPF Target Practice.

When I first started getting into Silverlight 2, my goal was to reproduce the same application in Silverlight. However, due to limitations (specifically a lack of Triggers), the only way to implement the animation would be in code. I moved forward with learning how to do the animation that way (and implemented some pretty cool visuals in my application at work), but I never posted the results since they missed the goal of using XAML only.

Silverlight 3 has some additional assemblies available that allow you to implement the triggers and fire off animations. So, in an entry in the near future, I'm planning on posting the Silverlight 3 version of Target Practice. So be sure to stay tuned!

Installation
To use Silverlight 3, you'll need Visual Studio 2008, plus the Silverlight 3 bits. Start at the Silverlight site here: http://silverlight.net/GetStarted/. As mentioned above, you want Expression Blend 3 (there are trials available if you don't want to purchase the full suite). Be sure to take a thorough look through the release notes as well.

Wrap Up
So, like most things in life, there is the bad along with the good. I'm hoping that by the time Visual Studio 2010 comes out, we'll have some better options available. In the meantime, the Silverlight 3 does have a lot to offer (I just scratched the surface with a few items that interested me).

Keep learning!

Saturday, June 13, 2009

More Silverlight Part 2 - User Controls & Events

The story so far: In More Silverlight Part 1, we created a Silverlight 2 application and a WCF service. We then used a DataTemplate and various ValueConverters to format and display the data in the ListBox.

Here's what the app looked like when we left off:

(Click image to enlarge)


Now, we're going to move on, first by creating a Detail panel, then abstracting out the ListBox to a User Control, and finally creating an Event that will let us know when a new Person record is selected.

Creating a Detail Panel

We'll start by adding a Detail panel that shows the First Name, Last Name, Birth Date, and Age for a single Person (the Person selected in the ListBox). This will be a StackPanel that is in the 2nd column of the Grid in our Page.xaml.

(Click image to enlarge)


The code is pretty self-explanatory. We set up TextBlocks to serve as labels for the data, and TextBlocks with data binding to hold the data. You'll notice that we are using the same DateConverter and AgeConverter that we used in the ListBox.

Getting Data into the Detail Panel

We want the Detail Panel to update whenever the selection changes in the ListBox. To do this, we'll hook up a "SelectionChanged" event to the ListBox. As a reminder, you can just type "SelectionChanged=" and Visual Studio will give you the option to add a New Event Handler.

(Click image to enlarge)


Now, we'll navigate to the Event Handler in the Page.cs file. What we need to do here is set the DataContext of the DetailPanel. But the question is, what should we bind to? Do we need to make a service call?

The answer comes through the fact that Silverlight data binding is extremely flexible. We can bind to any object, including an object that exists somewhere else on the page. In this case, we want to bind to the Person that is selected in the ListBox. So, we do just that.

(Click image to enlarge)


A couple of things to note here. First, you see that we are getting the SelectedItem for the ListBox and then casting it as a Person. What you should be aware of is that this may result in a null value. The SelectionChanged event will fire whenever the currently selected item changes; this includes when an item is un-selected. When a ListBox is first loaded, the default is to have no selection. This event will fire, and the SelectedItem will be null.

In many circumstances, you will want to check the "var p" to see if it is null after the assignment. In our case, we will want to let p be null (we'll see why in just a bit).

After we get the SelectedItem cast as a Person, we just assign this as the DataContext of our DetailPanel. Pretty straightforward, huh? Here's the result:

(Click image to enlarge)


To see how the nulls are handled in the Event, simply click the Button again. This will clear the selected item in the ListBox, which will in turn clear out the DetailPanel data.

Creating a User Control

But what if we want to re-use the Person ListBox multiple places in our application? Rather than duplicating code, it would be better to abstract out this piece as a separate User Control. That's what we'll do right now.

Step 1: Add a new User Control to the Silverlight project
Right-click on the Silverlight project, select "Add", then "New Item". From the dialog, select "Silverlight User Control" and name it "PersonListControl". This will create a default PersonListControl.xaml and PersonListControl.cs that look very similar to what we started with for Page.xaml/Page.cs. This is because Page is also a Silverlight User Control.

Step 2: Cut the StackPanel xaml from Page.xaml to PersonListControl.xaml
We'll be moving everything from the first Grid column of Page.xaml to the new user control. Just cut the entire StackPanel (the one that has Grid.Column="0"), and paste it over the Grid (LayoutRoot) in PersonListControl.xaml. This will leave us with a StackPanel as the root element of the user control. Note: after pasting it in, you will want to remove the "Grid.Column" attribute. The app will still run with it there, but it's better to keep the xaml as clean as possible.

Step 3: Copy the UserControl.Resources Section
The xaml that we moved in the step above makes use of the Converters we created earlier. This means that our new user control needs to have references to these as well. The easiest way is just to copy these from the Page.xaml. Note that we are doing a copy (not a cut) because these are used in the DetailPanel that is staying on Page.xaml.

Copy the "xmlns:local=" namespace and the entire "UserControl.Resources" sections with all three converters to PersonListControl.xaml.

Step 4: Change the Size
Our new UserControl will need to fit in the first column of our main Grid, so we'll want to change the sizes a bit. Change Width to 240 (to allow for a little bit of padding) and the Height to 300.

Step 5: Move the Event Handlers
The xaml that we moved contained 2 Event Handlers: one for the ListBox selection changed event, and one for the Button click event. Now we'll move the Event Handlers as well.

From the Page.cs file, cut the "PersonList_SelectionChanged" and "GetPeopleButton_Click" methods and paste them into PersonListControl.cs. One thing to note: since the PersonList_SelectionChanged event directly references the DetailPanel, this won't compile. For now, just comment out the 2 lines in this Event Handler. We'll be re-implementing this a little later.

You should be able to build now, but if you run the application, you will find that we still need to place the new user control onto our main Page.

Step 6: Using the User Control
Actually using the new user control on our main Page couldn't be easier. In the spot in our Page.xaml where we used to have a StackPanel (in the first Grid column), we will now have our control:

(Click image to enlarge)


Notice that this uses the "local" prefix (the same as our Converters) since everything is in the same namespace. If we were to split out the User Control into a separate namespace, then we would need to add a new xmlns and give it a different alias to use.

We can now run the application, and the ListBox will look just like it did before. If we click the Button, it will fetch the Person list and display it. The application doesn't work completely, though. We can't get the data into the DetailPanel. For that, we will need to expose an Event in our new User Control.

High Level Event Overview

Before we create the Event, let's take a look at how we'd like it to work. What we want to do is get the Person that is selected in the ListBox and display it in the DetailPanel. The problem is that the ListBox and DetailPanel are now in different scopes. So, we need to get the Person from the ListBox to the DetailPanel somehow. We'll do this by exposing an Event in the ListBox that has the selected Person as part of the EventArgs.

We'll need a custom EventArgs class that will hold the selected Person. Then we'll set up an Event on our new User Control that we can hook in to from our Page.

Custom EventArgs

We'll create the custom EventArgs class in the PersonListControl.cs file. You may want to abstract this out into its own file for other projects, but we won't do that here. We'll descend from RoutedEventArgs (which is a little more specific than EventArgs and is commonly used in Silverlight and WPF). Our custom EventArgs only needs to have a single Property (SelectedPerson) and a contructor that takes a Person as a parameter. Here's the completed code:

(Click image to enlarge)


Declaring the Event Handler

Next, we need to declare the Event in our PersonListControl class. We can do this with a single line of code:

(Click image to enlarge)


Note that there are several ways to make this declaration, including using "delegate" syntax. The syntax used here is the most compact. You'll see that we are using our custom EventArgs class as a generic type. Our Event is called "SelectedPersonChanged".

Invoking the Event Handler

To invoke the Event Handler, the convention is to create a method called OnEventName -- in our case "OnSelectedPersonChanged". Take a look at the code below:

(Click image to enlarge)


If the comments look familiar, it's because they came straight from the Microsoft Help file. They aren't really applicable for this particular application because we're not making descendant classes or doing complex invokation, but it's good to use the "safe" version so that we can get used to it.

You'll see that we are using our custom EventArgs as a parameter for this method. And as noted in the comments, we are making a copy of the handler first. This is because we can only invoke handlers that are actually hooked up to something (i.e. not null). If the handler is null, then we do not want to do anything (and thus we have the null check). The reason that we make the copy is that it is possible that the handler is deleted between the time we check for null and the time we invoke the method. If we make a copy, then we are acting on a snapshot in time, and so eliminate this possibility.

Raising the Event

Now we need to actually raise the event. We will do this in the "PersonList_SelectionChanged" method (the one that we commented out earlier). We will get the SelectedItem from the ListBox and cast it to a Person -- just like the old ListBox SelectionChanged handler. Then we'll use that Person to create the custom EventArgs and pass it to the OnSelectedPersonChanged method.

(Click image to enlarge)


Notice that it is possible for the Person to be null (as we discussed above). This is okay. If there is no SelectedItem, then we will pass the null through the Event and ultimately to the DetailPanel (as we'll see next). Be sure to build everything to make sure that there are now errors. If you run, you still won't see any difference. Yet.

Using the Newly Exposed Event

Now we'll go back to our Page.xaml to hook up the new Event. You'll notice that if you start typing "Select" in the PersonListControl element, IntelliSense will show the Event. Like other events, if you type "SelectedPersonChanged=", Visual Studio will let pop up "New Event Handler" (as we saw above). If you do this, you'll end up with something like this:

(Click image to enlarge)


Finally, we'll navigate to the event handler in the Page.cs file. Since the custom EventArgs exposes a SelectedPerson object, we just need to assign this to the DataContext of the DetailPanel.

(Click image to enlarge)


If you run the application now, you'll see a fully functioning Person ListBox and DetailPanel.

(Click image to enlarge)


This will behave the same as above. If you click the Button again, the DetailPanel is cleared. This is because the SelectedItem is cleared when the ListBox is loaded. Because the SelectedItem changed, the Event fires. And because there is no SelectedItem, the EventArgs contains a null SelectedPerson. This results in a null for the DataContext for the DetailPanel (which is what we want here). You may need to rework this if you need different behavior.

Summary
We've taken our application and abstracted out a significant part of it into a separate User Control. Then we implemented an Event on that User Control that we can use when we add the element to our Page. If we were to have several different forms that needed this same Person ListBox, we can simply add the custom User Control and get all the same functionality. We even have an Event to hook into so we know when the selected Person changes. These are just the basics, of course. For a production app, we would want to add Error handling and other such things.

As you can see, Silverlight has several powerful features that allow us to create flexible and well-designed applications. Since pretty much everything in Silverlight is a User Control, it's possible to nest these elements within each other and come up with some interesting abstractions in our UI.

Happy Coding!

Saturday, June 6, 2009

More Silverlight Part 1 - Data Templates & Value Converters

I've pretty much finished up my Silverlight 2 project at work, so I thought I'd share a few more useful things that I've come across. This time, we'll take a look at Data Templates (which make List Boxes extremely flexible) and Value Converters.

Setting Up the App

We're going to start by building a application similar to what we built in the last few posts: a Silverlight 2 application that gets data from a WCF service. Start by following Steps 1 - 3 from this post. I'll point out where we'll make a couple of changes.

Step 1: Create a New Silverlight Application
We'll call it "TemplatesConvertersEvents" this time. Let it create the ASP.NET hosting site as well.

Step 2: Build a WCF Service

Step 2a: The WCF Service Contract
We'll create the same PersonService, but we'll add a new field "BirthDate" to the Person class. See the Service Contract below:

(Click image to enlarge)


Step 2b: The Service Implementation
Again, this will look pretty similar. We'll just add a BirthDate value to each of the Person objects.

(Click image to enlarge)


Step 2c: WCF Service Configuration
Same as last time. Make sure to change the binding from "wsHttpBinding" to "basicHttpBinding".

Step 3: Add the WCF Service Reference to the Silverlight Application

Step 4: Update the XAML.
This is pretty similar to the previous examples, with just a few differences. Check out the code sample below for Page.xaml. Then we'll walk through it.

(Click image to enlarge)


Start by changing the Width and Height properties of the page (500 x 300). Then replace the default Grid with a Border. The Border contains a 2 column grid. We'll be concentrating on the first column here (the 2nd column will be used in Part 2). The Grid contains a ListBox.

Notice that the ListBox looks a little different. We are no longer using the "DisplayMemberPath". Instead, we have an ItemTemplate that contains a DataTemplate. The DataTemplate is simply a container that can hold whatever content you like. For now, we'll just include a TextBlock that is bound to the FirstName field. This will have the same effect as if we were to set the DisplayMemberPath. One thing to be aware of: the DisplayMemberPath and ItemTemplate are mutually exclusive; if you try to include both, you will get an error.

Finally, we have a Button that looks similar to our previous examples. As a reminder, to add the Click handler, just type "Click=" and Visual Studio will pop up an option for "New Event Handler". This will create a handler based on the control name and put the stub in the code-behind.

Next we implement the handler. You can right-click on "GetPeopleButton_Click" and choose "Navigate to Event Handler" and it will take you to appropriate spot in Page.cs. The handler implementation should look like this (again similar to what we've seen before):

(Click image to enlarge)


Another reminder: you will need to add the "using" statement for the PersonService. If you type in the code above, you can place the cursor on "PersonServiceClient", then press Ctrl+. to bring up the option to add the "using".

You should be able to build and run the application now. After you click the button, the results should look like this:

(Click image to enlarge)


Expanding the Data Template
Now we'll see the power that the ListBox has by expanding the DataTemplate a bit. The DataTemplate can only have a single child element, so if we add multiple items, we'll need to wrap them in some sort of container. We'll use a set of nested StackPanels -- some vertical and some horizontal.

(Click image to enlarge)


This is fairly straightforward XAML. Note that we have multiple TextBlocks that are databound and a little bit of formatting. Here's what we get when we run the app now.

(Click image to enlarge)


Creating a Value Converter
One thing I don't like about the output is the format of the BirthDate field. To take care of this, we'll use a value converter. A value converter is simply a class that implements the IValueConverter interface (profound, eh?). The interface consists of 2 methods: Convert and ConvertBack. An incoming value is passed in as a parameter; all you need to do is do the conversion and return the new value.

Our DateConverter isn't going to be that interesting, but it's a good place to start (then we'll look at something a little more challenging).

In the Silverlight project, add a new Class. I've called mine "Converters.cs" because I'll use the same file to hold all of my converters. Then we'll rename the class from "Converter" to "DateConverter" and add the IValueConverter interface. IValueConverter is in the System.Windows.Data namespace, so you'll need to add this to the "using" block as well.

As we've done before, we'll just right-click on "IValueConverter", choose "Implement Interface", then "Implement Interface" again. This will put the "Convert" and "ConvertBack" method stubs into our class. We'll only be doing one-way conversion (read-only data), so we will only implement "Convert". If you had a TextBox or other editable control, then you would also implement "ConvertBack" which reverses the process. Here's our code:

(Click image to enlarge)


Since the "value" parameter is of type object, we'll need to start off by casting it to the inbound type that we are expecting (DateTime in this case). Our outbound type is simply a string, so we'll call the ToString function with a formatting string that we like. Note that there are additional options (some that are especially useful for Date conversions) by using the "parameter" and "culture" parameters. Take a look at the Microsoft Help file to get more information on those.

Using a Value Converter
So, now that we have a DateConverter, how do we use it? First, we'll need to add the namespace to our xaml (see below). Again, VisualStudio is helpful here; if you type "xmlsns:local=", then you will get a list of namespaces that are in the project, including everything that appears in the project References. We'll select the project namespace "TemplatesConvertersEvents". You can use whatever alias you like for the namespace; "local" is a convention for items contained within your project.

The next step is to add our DateConverter as a Static Resource.

(Click image to enlarge)


Now all that's left is to add the Converter to the Binding declaration in our TextBlock.

(Click image to enlarge)


If you run the application now, you'll see that we have a nicely formatted mm/dd/yyyy date for the BirthDate field. Let's try something a little more complex.

An Age Converter
In addition to the BirthDate, I'd like to display the age of the Person as well. The problem is that we don't have an Age field. So, instead, we'll use the BirthDate field to calculate the age. We'll just add another class (AgeConverter) to the Converters.cs file.

(Click image to enlarge)


We won't worry about the specifics of the code too much (I'm sure that I'll get letters with better ways to calculate age). The main point is that we are taking a DateTime (BirthDate) and converting it to an Integer (Age). Well, actually, we're converting it to a string for display purposes, but you get the idea.

Using the AgeConverter is just the same as the DateConverter. Add a Static Resource (I called mine "myAgeConverter") and then use it in a Binding statement. Notice that we are still Binding to the BirthDate field; by using the AgeConverter, we control what we will actually display. Here is a portion of our expanded DataTemplate (we appended the Age portions to the section with the BirthDate).

(Click image to enlarge)


If you run the app now, you'll see both the BirthDate and the Age are included.

One More Converter
As one final step, we'll get a little more creative with our converter. So far, we've more or less just converted a value from one format to another. This time, we'll convert to a completely different type. I want to display ages that are over 30 in a green font and 30 or under in blue. We'll do this by changing the BirthDate to a Brush.

Once again, create a new class "AgeBrushConverter" in the Converter.cs file. The code looks like the "AgeConverter" code, but instead of returning the age, it uses it to create a SolidColorBrush:

(Click image to enlarge)


For the implementation, our final "Resources" section looks like this:

(Click image to enlarge)


And our final DataTemplate (notice that we are using the AgeBrushConverter for the Foreground property of the TextBlock):

(Click image to enlarge)


And our final result:

(Click image to enlarge)


Summary
We've taken a chance to look at DataTemplates and ValueConverters to add flexibility to how we display our data in ListBoxes. DataTemplates can contain complex layouts (including Grids and Images, if desired). ValueConverters also go beyond simple formatting (like Dates and Currency); they can also be used to show or hide items (think of Binding a value to the "Visible" property) or even to add text formatting to differentiate values (such as using red for negative numbers and black for positive, or possibly graying-out inactive items).

Hang on to this application. In Part 2, we'll take a look at creating a custom user control that abstracts out part of the functionality and exposes an event that we can use.

Tuesday, May 12, 2009

Silverlight 2, WCF, and Lambda Expressions - Part 2

In Part 1, we set up a Silverlight 2 application that consumes a WCF Service. In Part 2, we'll look at a problem with the implementation and different ways of solving it -- ultimately ending with Lambda Expressions. Hopefully by the time we get done, you'll be comfortable with how lambda expressions work and how to use them to make your code cleaner and easy to understand.

Where We Left Off
Here's a quick reminder of what we did last time:
  1. We created a WCF Service that is Silverlight 2 compatible.
  2. We added a reference to the service in a Silverlight application.
  3. We created a UI (Button and ListBox) to call the service and show the results.
  4. We called the WCF Service and hooked up the Completed event to an event handler.

The Page.xaml.cs file we finished with is as follows:

(Click image to enlarge)

And the UI:

(Click image to enlarge)

A Problem
There is a small problem with the UI. After calling the service (by clicking the button), the list gets populated with the names. You can select a name in the list by clicking on it. But if you click the button again, the list refreshes and the selection goes away. We want to update this so that the selected item is maintained when the service is called again.

Solution #1 - Using the Event Handler
The SelectedItem of the ListBox gets cleared when the service is called because we are re-binding the data. From the ListBox's point of view, it is getting a new object to bind to. When the old object is un-bound, the selected item goes away and doesn't come back.

We'll solve this by simply saving off the SelectedIndex of the ListBox before we make the service call. Then after the service call returns, we will reassign the SelectedIndex. (This is assuming that the order of our items is not changing, and we're not getting any new items -- you can extend this basic functionality for more complex situations).

Since we need to save off the SelectedIndex in one method (the Button Click event handler) and then use it in a different method (the Service Completed event handler), we'll need to create a class-level variable to hold this information. See the code below:

(Click image to enlarge)


You'll see 3 new lines of code to get this to work:
  1. private int ehListIndex;
    The class-level variable
  2. ehListIndex = EHList.SelectedIndex;
    Saving the index
  3. EHList.SelectedIndex = ehListIndex;
    Re-assigning the index to the list box

If you re-run the application, you will see that if you make a selection in the list box, that selection is maintained when you call the service multiple times.

Solution #2 - Using an Anonymous Delegate
Now, we'll try this again using an anonymous delegate instead of an explicit event handler. You'll see why this is an advantage in just a bit.

We'll update our XAML by adding another StackPanel to our Grid.

(Click image to enlarge)

You'll notice that this section looks almost identical to the EventHandler UI section. Here's a summary of the differences:

  • The 2nd column of the Grid is specified in the StackPanel.
  • The Names of the ListBox and Button start with AD (for anonymous delegate) instead of EH.
  • The ListBox border is blue (just to make it different).
  • The button Content is "Anonymous Delegate".
  • There is a new Click handler for the button (you can look at the hint in Part 1 about letting IntelliSense create the handler for you).

So, what is an anonymous delegate? In our case, it is an in-line definition of an event handler (for the service callback). This is defined by using the "delegate" keyword, then a set of parentheses with the appropriate parameters, then a set of curly braces with the method implementation. The implementation will look just like in our callback when using the EventHandler.

Here's the initial implementation:

(Click image to enlarge)

What you will notice is that that the first and last lines are the same as our previous button click event. You'll also notice that the parameters for the anonymous delegate ("object" and "GetPeopleCompletedEventArgs") matches the parameters in the explicit event handler we implemented earlier. Finally, the body of the delegate matches the body of the event handler callback.

I know what you're thinking: big deal. Other than "in-lining" some code, exactly what did we gain here? We're about to find out.

We still have the same issue we had earlier with the ListBox SelectedIndex. The advantage to using an anonymous delegate is that any variables in the outer method can be accessed in the delegate implementation. This means that instead of using a class-level variable to store the index, we can use a local variable. Check out the completed code below:

(Click image to enlarge)


You'll see that we now have a local variable named "adListIndex" that is assigned outside of the delegate and then used inside of the delegate. We've just eliminated the need to have a class-level variable.

Solution #3 - Using a Lambda Expression
Let's take this one step further. Instead of using an anonymous delegate, we'll use a lambda expression. First, update the UI. This XAML is very similar to the anonymous delegate section:

(Click image to enlarge)


The same items are updated as above: grid column, element names, border color, button content, and click event.

So, now lets take a look at lambda expressions. There are 2 types of lambda expressions: statement lambdas and expression lambdas. Both use the same syntax (consisting of 3 parts):
  1. Parameters
    These are normally enclosed by parentheses (although, parentheses can be excluded if there is only a single parameter).
    The parameter types may be excluded if the compiler can determine the correct types.
  2. =>
    This is known as the "goes to" operator and denotes that this is a lambda.
  3. Statement(s) or Expression(s)
    A statement lambda has one or more operations wrapped in curly braces. The statement(s) denotes some type of work to be done.
    An expression lambda has one or more expressions (that return true or false) wrapped in curly braces. These are used extensively in LINQ.
    If there is only a single statement or expression, then the curly braces can be excluded.
We'll be working with an Statement Lambda. The first steps to convert the anonymous delegate to a lambda expression are to remove the "delegate" keyword and place the "=>" operator between the parameters and the method implementation. Take a look at the "LEButton_Click" method below and compare it to the first "ADButton_Click" method above:

(Click image to enlarge)


But, as we noted above, if the compiler can determine the parameter types, then we don't need to include them in our code:

(Click image to enlarge)


If you hover over the "s" and "ea" parameters, you will see that Visual Studio recognizes these as being of type "object" and "GetPeopleCompletedEventArgs" respectively. This means that we still have strongly-typed objects. The same is true of "ea.Result". This is the strongly-typed collection that is returned from our WCF Service.

As a final step, we can add the SelectedIndex handling code into the mix:

(Click image to enlarge)


If you run the application, you will see that all three list boxes behave the same way. All three list boxes will keep the selected index between service calls.
What We Learned
We took a look at 3 different ways to solve a particular UI issue. We see that both the Anonymous Delegate and Lambda Expression solutions have the advantage of being able to use a local-scoped variable (thus, keeping our class-level clutter-free). In addition, we see that the Lambda Expression solution has the advantage of not needing to include the parameter types. This is especially helpful if you have a delegate that has the standard 2 parameter signature ("object" and "SomeKindOfEventArgs"); you don't need to know the particular EventArgs class -- just let Visual Studio figure that out for you.
My advice: become familar with Lambda Expressions. You will find that when used judiciously, they can help keep your code understandable and easier to maintain.

Friday, May 1, 2009

Silverlight 2, WCF, and Lambda Expressions - Part 1

This is a 2-part series in using WCF with Silverlight 2. Part 1 is about creating a Silverlight-compatible WCF service and consuming it in a Silverlight application. Part 2 is about lambda expressions, but uses the foundations in Part 1.

Step 1 - Create a New Silverlight Application
First we'll create a new Silverlight application. In Visual Studio, create a New Project, and select the "Silverlight Application" template. I've called mine "SilverlightWithWCF", so that's what you'll see in a couple places throughout the post.

Visual Studio will prompt you with the following:
(Click image to enlarge)


We want to include a new ASP.NET Web Application Project, so we'll leave the defaults as-is. Other options include "ASP.NET Web Site" and possibly "ASP.NET MVC" (if you have the MVC bits installed). In addition to using the ASP.NET application as a test site for the Silverlight application, we will use it to host our WCF service.

Step 2 - Build the WCF Service
We'll add a new WCF Service at this point. Right-click on the Web Application project ("SilverlightWithService.Web" in my case), and choose "Add", then "New Item". Select the WCF Service. We'll name ours "PersonService.svc". See below:

(Click image to enlarge)


You'll notice that there are 2 options we could choose from: "WCF Service" or "Silverlight-enabled WCF Service". You might wonder why we didn't pick the Silverlight one. The answer is that I wanted to look at the standard WCF Service, so that you will know what to do if you already have an existing WCF Service that you want to hook into. I'll point out the difference below when we look at the Web.config file.

Step 2a - The WCF Service Contract
WCF Service consist of 3 main pieces: the Service Contract, the Service Implementation, and the Service Configuration. First, we'll look at the Service Contract.

The contract is simply an interface decorated with a few specific attributes. Visual Studio will create an I[ServiceName].cs file that contains the placeholder contract. If you open the IPersonService.cs file, you'll see an interface that is decorated with the [ServiceContract] attribute. Visual Studio also gives you a sample method called "DoWork". You'll notice that this is decorated with the [OperationContract] attribute. You can think of this as being analogous to the [WebMethod] attribute that we used in ASMX Services. The [OperationContract] attribute denotes which methods will be exposed to the outside world.

We're going to replace the "DoWork" method with a "GetPeople" method. Take a look at the completed code below, and we'll step through it:

(Click image to enlarge)


You'll notice that our method returns a List of Person. Person is a custom class, and so we need to include the definition of the class as well. You'll notice that we have a separate public class called "Person" that is decorated with the [DataContract] attribute. The class consists of 2 public properties (FirstName and LastName) that are each decorated with the [DataMember] attribute. The DataContract and DataMember attributes let the WCF sub-system know that it needs to include this type in the definition of the Service.

On a side note, the [DataContract] and [DataMember] attributes can be excluded in this particular case. .NET 3.5 SP1 will automatically include the type definition for public classes that have automatic properties and a public default constructor. This was added to facilitate Entity Framework. I'll leave it as an exercise for the reader to do further research into this.

The contract only tells what the service will do, not how it does it. For that, we'll need to look at the service implementation.

Step 2b - The WCF Service Implementation
The WCF Service implementation is a class that implements the WCF interface. Open up the "PersonService.svc.cs" file (note: you can simply double-click on the "PersonService.svc", and it will open the .cs file).

You'll see that the class "PersonService" implements "IPersonService" and still has the placeholder "DoWork" method from the stub that Visual Studio created. Delete this method. We'll let Visual Studio add the stubs for the updated interface. Simply right-click on "IPersonService" and select "Implement Interface", then "Implement Interface" again (we won't cover "Implement Interface Explicitly"). This will create a stub for the "GetPeople" method. Here's the implementation:

(Click to enlarge image)


This simply creates a List object and populates it with some Person instances. In real life, you'll probably be doing something more complex (such as accessing a database).

Next comes the configuration.

Step 2c - WCF Service Configuration
Open up the Web.config file, and then navigate to the "system.serviceModel" section (at the bottom). The only thing that you'll need to do is update the binding to "basicHttpBinding" (from "wsHttpBinding"). See below:

(Click image to enlarge)


Remember when I promised to show the difference between "WCF Service" and "Silverlight-enabled WCF Service"? This is it. Silverlight 2 is limited in that it can only use WCF Services that use the "basicHttpBinding". This is the same binding that ASMX services use. (Note: Silverlight 3 will not have this limitation). The "Silverlight-enabled WCF Service" defaults to basicHttpBinding, while "WCF Service" defaults to wsHttpBinding. If you have an existing service, you'll just need to change this value (or add an endpoint that uses this binding).

Note: This is a very important step. If you try to add a Service Reference in a Silverlight application to a WCF Service that is *not* using basicHttpBinding, then the proxy will not work. Even better, you don't get any helpful error messages, just a rather obscure one. So, make sure you don't skip this step.

From here, we'll build everything just to make sure that things look good. This completes our updates to the Web Application. Next, we'll move on to the Silverlight application.

Step 3 - Add the WCF Service Reference to the Silverlight Application
We'll start in the Silverlight application by adding a Service Reference to our newly created service. Right-click on the Silverlight Application project ("SilverlightWithService" in our case), and choose "Add Service Reference". If you click the "Discover" button, it will search out the Services that are included in the Solution. We'll use the namespace "PersonService". See below:

(Click image to enlarge)


Before you click "OK", be sure to check out the "Advanced" button. This opens a dialog that lets you choose how collections are returned from WCF Service calls:

(Click image to enlarge)


You'll see that there are 4 options to choose from: Array, Generic List, Collection, and ObservableCollection. The ObservableCollection is preferred in Silverlight for data binding purposes, but you may want to experiment with the other options as well. It doesn't matter the actual collection type that is returned from the service; it will be converted to the type you select here.

Now that we've added our Service Reference, we'll take a look at the Silverlight UI.

Step 4 - Update the XAML
Next, we'll create the UI. Open up the Page.xaml file. We're going to be making a few changes to the default values and adding some controls of our own. The final layout may look a little odd. This is because we will be adding some more elements to this in Part 2.

Here's the final layout:
(Click image to enlarge)


Let's look at the XAML; then we'll go through it step by step:
(Click image to enlarge)


First, update the Width and Height of the UserControl to 600 and 200 respectively. Then we'll swap out the "Grid" root element for a "Border". Then add a Grid with 3 columns (the other 2 columns will be used in Part 2). Inside the first column is a StackPanel with a ListBox and a Button. The ListBox sets the ItemsSource to "{Binding}". This says that each ListBox item will be bound to each item in the collection. The data binding will use a DataContext that we set in code at runtime.

Next is the Button named "EHButton" (for Event Handler Button -- Part 2 will have 2 additional Lists and Buttons and these names will make more sense). When adding an event handler in XAML, Visual Studio will help you out a bit. If you type "Click=" and hit Ctrl-Space (or let Intellisense pop up on its own), you will have the option "New Handler" to pick from. This will automatically name the handler based on the control name, and then add the stub to the code. In this case, it will create "EHButton_Click" in the code and hook up event.

Now that our UI is laid out, let's put the last of the pieces together.

Step 5 - Call the WCF Service
Here's another short-cut. If you right-click on "EHButton_Click" (the event handler) in the XAML, one of the options is "Navigate to Event Handler". This will open up the Page.xaml.cs file and put the cursor on the "EHButton_Click" event handler.

First, add the WCF Service namespace to the "using" section. This will make the code more readable. The namespace is [projectName].[serviceNamespace]. In our case, it is "SilverlightWithService.PersonService".

Now, we'll go back to the event handler. Start by creating a new proxy object. The proxy is the service name with "Client" appended to the end. In our case it is "PersonServiceClient". Next we'll hook up the callback. Since all Silverlight calls are asynchronous, we have to call the service asynchronously (it's the only choice). Start by hooking up an event handler to the "Completed" event. Visual Studio helps you out with this, too. Type "proxy.GetPeopleCompleted +=", and you'll see Intellisense for creating a new event handler. If you press "Tab" twice, it will create the new handler, and add the implementation. This is a great short-cut. The last step is to call the service using the "Async" method. In this case, just call "proxy.GetPeopleAsync()". See completed button click event handler below:

(Click image to enlarge)


The final step is to implement the callback. This is as simple as getting the result of the call (in this case a List of Person) with "e.Result" in the code. Then we assign this to the DataContext of the ListBox in the UI. One thing to note, if you hover over "e.Result", you will see that it is actually of type ObservableCollection of Person. This is due to the selection we made when we added the Service Reference earlier. The completed Page.xaml.cs file is as follows:

(Click image to enlarge)


Step 6 - Build and Test
Let's build and run. What you should see is that when you click the "Event Handler" button, you will get a list of 5 names in the ListBox. This may take a few seconds for the Service to fire up and run -- remember we're running asynchronously here. Also note that the list only includes the First Name because we did not do a full data template; we just set the DisplayMemeberPath. It's easy enough to enhance yourself, though.

(Click image to enlarge)

Conclusion
You should have a pretty good idea of how to create a WCF Service and consume it with Silverlight 2. We've created a new WCF Service, ensured that it was Silverlight 2 compatible, created a Silverlight 2 application, added the Service Reference, updated the UI, and finally called the Service and bound the results to the UI. In Part 2, we'll be looking at other ways of handling the asynchronous calls.