Skip navigation

Lessons Learned Building Real-World Silverlight Applications: Part 1

Hard-won wisdom that will improve your Silverlight coding

Downloads
125397 Wahlin SilverlightDemos.zip

There's rarely a boring day working in the world of software development. Part of the fun associated with being a developer is that change is guaranteed, and the more you learn about a particular technology, the more you realize there's always a different or better way to perform a task.

I've had the opportunity to work on several different real-world Silverlight line-of-business (LOB) applications over the past few years and wanted to put together a list of some of the key things I've learned as well as key problems I've encountered and resolved. There are several different topics I could write about related to "lessons learned" (some of them more painful than others), but I'll keep it to three items for this article and cover additional lessons learned in a future article. The topics discussed were put together for a TechEd presentation I gave in June 2010.

The first topic covered relates to architecture best practices and how the Model-View-ViewModel (MVVM) pattern can save you time in the long run. When I was first introduced to MVVM, I thought it was a lot of work for very little payoff. I've since learned (the hard way in some cases) that my initial impressions were dead wrong and that my criticisms of the pattern were generally caused by doing things the wrong way. In addition to providing MVVM tips, I'll also jump into data-binding tricks in nested control scenarios and discuss how you can use animations and media to enhance LOB applications.

Lesson #1: Pick a Pattern and Stick to It
There's been a lot of talk about the MVVM pattern over the past year, and many Silverlight and Windows Presentation Foundation (WPF) applications are being built using this pattern. Like most developers, when I first started exploring Silverlight and building different prototypes, I put most of the code into the code-beside file. There's nothing wrong with doing that until it dawns on you one day that reuse is poor, maintainability is poor, and testability isn't exactly great either.

I've written about the MVVM pattern in DevProConnections previously and also have a post on my blog that will help get you started, so I won't go into great deal about the pattern here. The key players in the MVVM pattern are the Model, the ViewModel, and the View as shown in Figure 1.

The main lesson I learned while migrating applications to MVVM is that starting a new development project with the proper architecture ultimately saves time even if you feel like you're wasting more time initially. Adding code directly into a code-beside file is certainly easy and feels very productive, but as an application continues to grow, you'll start to find similar code being duplicated across screens instead of being shared.

MVVM provides an excellent pattern, and although it can be a little daunting at first, it's actually quite simple once the concepts are put into practice. If you're starting a new Silverlight LOB development project, I highly recommend taking the time to research and prototype a simple application using the MVVM pattern, then decide for yourself if it fits your scenario.

Ultimately I found that by sticking with a pattern (whatever pattern you feel is best for your application), code is simplified in many scenarios, data access and data storage code are kept separate from views, and code is easier to locate and refactor when changes need to be made. The sample application available with this article demonstrates a simple implementation of the MVVM pattern. Topics that the sample demonstrates include using ViewModels, declaratively binding ViewModels, binding data to ViewModel properties, using commanding, using an event bus for messaging, and using Expression Blend's InvokeCommandAction behavior. An example of integrating sample data into ViewModel classes is also shown.



Lesson #2: Data Binding and Nested Controls
Silverlight has an excellent data-binding engine available that integrates nicely with the MVVM pattern and also saves a lot of time when used correctly. Instead of writing code to map submitted values from a form, you can take advantage of two-way binding to automatically map control values to object properties using declarative XAML bindings. You can find additional information about Silverlight's data-binding framework as well as a comparison of ASP.NET control-centric binding to Silverlight's data-centric binding can be found on my blog. I've also written about this subject in a previous issue of DevProConnections if you're interested in more details; see the sidebar at the end of this article for a list of relevant articles.

Although Silverlight's data-binding framework works very well, there are a few situations where it can be difficult to work with, especially as applications grow larger and more and more user controls are created. One challenge you may run up against occurs when working with nested controls. Consider the scenario shown in Figure 2.

The ViewModel class contains a Branches property that ultimately needs to be bound to ComboBox controls nested inside of DataGrid rows. Normally this is simple since you can use syntax such as the following to get at the ViewModel's Branches property when nesting controls inside of other controls such as the DataGrid:

<ComboBox ItemsSource="\\{Binding Source=\\{StaticResource ViewModel\\},Path=Branches\\}" />



This assumes that the ViewModel is declaratively defined in the view's resources section and bound to the view's DataContext (see the article's sample application for an example).

Things get more complicated if the DataGrid is nested inside of a child user control. When a user control is nested as a child, it gets its own resources collection, which means that the ViewModel defined in the parent (Page is the parent in Figure 2) isn't directly accessible using the StaticResource binding shown earlier. In real-world applications it's quite common to break up pieces of a view into separate user controls, so what do you do when you need to access a resource that is effectively out of scope?

After fighting with this issue for a while, I decided to "proxy" the data context defined in the parent down to the child user control much like the ScriptManagerProxy proxies the ScriptManager in ASP.NET AJAX. I ended up creating a DataContextProxy class that exposes the parent data context inside of the nested control, making it easy to get to the ViewModel without having to write any C# code to do it. Figure 3 shows the DataContextProxy class. Looking through the code, you'll see that the Binding object's Source property is set to the DataContext inherited from the parent.

The DataContextProxy class can be defined in the child user control using the following syntax (note that I left out the standard Silverlight namespaces to keep the code as compact as possible):

<UserControl x:Class="SilverlightDemos.UserControls.CustomersGrid"
    xmlns:controls="clr-namespace:SilverlightDemos.Controls;">
    <UserControl.Resources>
        <controls:DataContextProxy x:Key="DataContextProxy" />
    </UserControl.Resources>
     ...
</UserControl>


With the DataContextProxy in place, the ViewModel resource defined in the user control's parent can be accessed and the Branches property can be bound to ComboBox controls nested inside of a DataGrid, as shown next:

 

<ComboBox ItemsSource="\\{Binding Source=\\{StaticResource DataContextProxy\\},
   Path=DataSource.Branches\\}" DisplayMemberPath="Name" />


Notice that the binding identifies the DataContextProxy static resource as the source and that the Path is assigned to the DataSource property defined in the DataContextProxy class. Because the DataSource property stores the parent DataContext, you can get to any property defined in it. In this case, it means that we can go through the DataSource property to get to the Branches collection defined in the ViewModel. I suspect that Microsoft will simplify this process in a future version of Silverlight, but until then the DataContextProxy provides a simple way to deal with more complex nested control scenarios.

Lesson #3: Notify Users of Successes (and Failures)
This particular lesson is extremely simple to implement but something that I really hadn't thought about doing in Windows Forms and ASP.NET applications. Before getting into more details, ask yourself how you currently notify a user when a particular operation succeeds or fails. In the past I've updated a label control to show a message or popped up some type of dialog box. Dialogs in particular aren't very efficient when it comes to user workflow, especially if the operation succeeded since the user has to click them to move on. Updating labels is certainly valid, but in many applications they stay on screen even after the operation has finished successfully.

In one of the applications my company is building, we decided to take advantage of Silverlight's animation features to notify users when operations succeeded or failed. We also integrated subtle media features during this process. You'll see that it's a very simple process but something that can be quite effective. Sometimes it's the simple things that users appreciate the most.

To start, we created a Border control in Expression Blend that was above the screen (in a location that the user can't see). When an operation occurred, we added code to start an animation that moved the Border into view for a few seconds and displayed a message. The animation then moved the Border back out of sight. While the animation is playing, we also call Play() on a MediaElement to play a sound that simulates success or failure. Users who don't have speakers available won't hear the sound. of course. but those who do have speakers quickly know what happened without even looking at the screen. Windows does this a lot, so we decided that it made sense in Silverlight applications as well. Figure 4 shows an example of a simple Storyboard to animate a Border control as an operation occurs.

In addition to the Storyboard, two MediaElement controls were also added into the XAML:

<MediaElement x:Name="SuccessMediaElement" AutoPlay="False"
                Source="/SilverlightDemos;component/Assets/Sounds/success.wma" />
<MediaElement x:Name="FailureMediaElement" AutoPlay="False"
                Source="/SilverlightDemos;component/Assets/Sounds/failure.wma" />


As a user saves data in a DataGrid, completes a form, or performs another type of operation, the application will start the Storyboard and change the text and color defined within the Border depending upon what happened. It will also play the appropriate MediaElement. Figure 5 shows the code to handle these tasks.

If the operation succeeds, the message shown in Figure 6 will temporarily be displayed. If the operation fails, a similar message along with potential validation messages will be shown, but the bar will be turned to red and the message will be changed to Oops… looks like something went wrong!". A message box, child window, or validation message is certainly appropriate if an error occurs, so that the user gets additional details about how to fix the problem.

The lesson we learned while working with end users was that making messages as unobtrusive as possible helped them stay focused and avoided unnecessary mouse clicks. We also learned that many users like to be explicitly notified when an application succeeds rather than having to assume a particular operation worked simply because no errors were shown. Although this particular concept isn't earth shattering, it is different than the status messages typically shown in applications.

More Lessons to Come
I've shown you a few key lessons I've learned building real-world Silverlight applications over the years. In part 2 of this article series, I'll dive into additional lessons learned and demonstrate other tips and tricks that you can use. Until then, happy coding!


Dan Wahlin ([email protected]), a Microsoft MVP for ASP.NET and XML web services, founded the XML for ASP.NET Developers website and The Wahlin Group (www.TheWahlinGroup.com), which specializes in .NET, Silverlight, and SharePoint consulting and training solutions.


Learn more about MVVM, data binding, and building LOB applications:

"Building Line of Business Applications"
"Simplify Silverlight Data Binding in Nested Controls"
"Integrating ViewModel Classes into Silverlight Applications"
"Build Loosely Coupled Silverlight Applications"
"Silverlight Data Binding"
"Silverlight Data Validation"

Learn more about Expression Blend:
"Expression Blend's SketchFlow Syncs Up Silverlight Designers and Developers"
"Expression Blend for WPF: Where's the Training?"

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish