Silverlight Tutorial Part 6: Using User Controls to Implement Master/Detail Scenarios

This is part six of eight tutorials that walk through how to build a simple search client application using Silverlight 2.  These tutorials are intended to be read in-order, and help explain some of the core programming concepts of Silverlight. 

<Download Code> Click here to download a completed version of the Bing Images Search sample. </Download Code> 

<Download Code> Click here to download a completed version of the Digg Search sample. </Download Code>

Understanding User Controls

A fundamental design goal of XAML is to enable developers to be able to easily encapsulate UI functionality into re-usable controls.  Developers can implement new custom controls by deriving a class from one of the existing Control classes (either a Control base class or from a control like TextBox, Button, etc).  Alternatively they can create re-usable User Controls - which make it easy to use a XAML markup file to compose a control's UI, and which are easy to implement.

For our search application, we want to implement a master/details scenario where the application allows an end-user to search on a topic, populate a list of stories related to that topic, and then enable them to select a story to bring up details about it.  For example, selecting the below story in the list:

would bring up this detailed view about the story:

We are going to implement this details view by building a "StoryDetailsView" UserControl that we'll display when a story is selected from our ListBox.

Creating a StoryDetailsView User Control

We'll start by right-clicking on our DiggSample project node in Visual Studio and by selecting "Add New Item".  This will bring up a new item dialog.  We'll select the UserControl item template and name the new control we want to build "StoryDetailsView":

This will add a new UserControl with this name to our DiggSample project:

Building a Basic Modal Dialog Using a User Control

We are going to use our StoryDetailsView control to effectively display a dialog containing story details.  When our story details user control displays we are going to want to have it appear on top of the other content on the page, and ensure that an end-user can't do other things with the page until they close the details view.

There are a couple of different ways we could implement this modal dialog-like behavior.  For this particular scenario we are going to start by opening up the StoryDetailsView.xaml user control and adding the below XAML content to it:

The first <Rectangle> control above is configured to stretch to take up all of the available space on the screen.  Its background fill color is a somewhat transparent gray (because its Opactity is .765 you can see a little of what is behind it).  The second <Border> control will then be layered on top of this Rectangle control, and take up a fixed width on the screen.  It has a blue background color, and contains a Close button.

When visible, our StoryDetailsView user control will currently display a UI like below:

We can implement the "CloseBtn_Click" event handler method in the code-behind file of the user control.  When pressed, the close button event handler will set the Visibility of the UserControl to "Collapsed" - which will cause it to disappear from the screen and return the user to the content below it:

 

Displaying our StoryDetailsView Control

An easy way to cause our StoryDetailsView user control to appear on the screen would be to simply add it to the bottom of our Page.xaml file, and set its default visibility to Collapsed (which means it is not visible when the application first loads):

We can then handle the "SelectionChanged" event from our ListBox control within the Page.xaml's code-behind class:

When a user selects a particular story in the list, we can use the ListBox SelectionChanged event handler to set the Visibility property of our ShowDetailsView user control to "Visible" :

This will cause our modal user control dialog to appear.  When the user clicks its "Close" button, it will disappear, and the user will be free to select another story and repeat the process.

Passing Story Data to our StoryDetailsView User Control

Ultimately we want our StoryDetailsView UserControl to display detailed information about the story that the end-user selected from the stories ListBox. 

Within our ListBox's "SelectionChanged" event handler (which is inside our page's code-behind class), we can gain access to the DiggStory data object that corresponds to the selected ListBox row by accessing the ListBox's "SelectedItem" property. 

One approach we could use to pass this DiggStory object to our StoryDetailsView UserControl would be to simply set the "DataContext" property on the User Control to the selected DiggStory data object immediately before making the user control visible:

We could then write code within our UserControl to procedurally use the DataContext to display results.  Or alternatively we could use databinding expressions to bind against its values. 

For example, we could update our StoryDetailsView XAML to display the Title of the selected story using a databinding expression like below:

And now when a user clicks a story in the list:

Our ListBox event handler will handle the selection, set the DataContext of the UserControl to the selected DiggStory object, and then make the user control visible:

Notice how the DiggStory title now appears in the user control because of the databinding expression we added to it.

Finishing our User Control Layout

Our sample above demonstrates the basics of how we can put together a simple master/details dialog workflow.  We can complete the StoryDetailsView display by adding more controls and databinding expressions to the User Control. 

We could update the StoryDetailsView user control to look like above by updating its <Border> control to have the following inner content:

No code changes are required after this.  Because we are using databinding to "pull" the values from the DataContext, we don't need to write any additional code.

Next Steps

We now have all of the core functionality and interaction workflow implemented for our search application.

The last step we are going to take is to tweak the UI of the application a little more.  Specifically we want to add a slightly more polished and customized look to the ListBox and Button controls.

To-do that let's go to our next tutorial: Using Control Templates to Customize a Control's Look and Feel.

26 Comments

  • This tutorials are great, thanks.
    Why you doesn't use BLEND to design the Grid, Textboxes and so on? Is it possible to do this with the actual version of BLEND?

  • Is it going to be possible to popup a real modal window, or, do you have to do it this way? This looks like the same thing they do in Flex.

  • It's not very clear how do you place the detail panel on top as a modal Dialog... willing to get the code and the Beta to check how you did it.

  • good tutorial~

    I guess how TextBlock show multiline.
    show me the way~

  • I'm unable to reference the user control ...the editor doesn't recognize this control. Am i missing something?

  • Set property TextWrapping="Wrap"

  • to show multiline, set the attribute "TextWrapping" of textblock "Wrap"

  • I also want to know how to reference the user control in another usercontrol.Can anybody help me?

  • To reference the Dig:StoryDetailsView you need to add

    xmlns:Digg="clr-namespace:DiggSample"

    at the top of the Page.xaml.

  • You have to add the reference below if your control can't be recognized.
    xmlns:Digg="clr-namespace:DiggSample"

    Hi Scott,

    Could you post the style codes of StoryDetailsView user control? In addition, HyperlinkButton doesn't work, if adding the binding of NavigateUril property. It's wired.

  • @Mike: You have to add the Namespace definition

    xmlns:Digg="clr-namespace:DiggSample"

    to the UserControl of the Page.xaml

  • Thursday, March 06, 2008 1:42 PM by Mike

    I'm unable to reference the user control ...the editor doesn't recognize this control. Am i missing something?

    >>>>>>>>> add this as a xml namespace to your page.xaml to solve it: xmlns:Digg="clr-namespace:DiggSample"

  • Problem solved Jeremy ... just add this
    xmlns:my1="clr-namespace:" in the Page's usercontrol (PARENT TAG), and replace with your project's name space.

    also in scott's example where the user control is embedded in the page's XAML remove "digg:" with "my1:" or what ever u name it in Page's user control tag.

  • -- Prev message --

    Hi Scott,

    Could you post the style codes of StoryDetailsView user control? In addition, HyperlinkButton doesn't work, if adding the binding of NavigateUril property. It's wired.

    -- --
    I handled the "GotFocus" event on the StoriesDetailView user control and casted the datacontext to a DiggStory and then manually set the HrefLink and that works. Direct databind doesn't seem to work because it's expected a "Uri" object not a "String".

  • What about "IsSynchronizedWithCurrentItem"? Can the item synchronization be implemented within XAML?

  • Hi Scott,
    Can you show us the detail styles of the StoryDetailsView panel?

  • Hello all,
    NavigateUri don't work.
    NavigateUri="{Binding HrefLink}

  • I also ran into the problem with the HyperlinkButton NavigateUri not working because it's binding to a string. Glad Dave noticed the issue.
    Just my 2 cents: The easy solution is to add another "get" property to the DiggStory class and expose the HrefLink as a Uri. then you can use the binding straight up, no need to handle any events.

  • Hey guys,

    In Scott's code, he changed the HrefLink type from "string" to "Uri". To accommodate that change, the "DisplayStories" in the Page.xaml.cs was altered:

    HrefLink = (string)story.Attribute("link"),
    becomes
    HrefLink = new Uri((string)story.Attribute("link")),

    Then it works flawlessly.

  • Hi Scott, GREAT walkthrough! I'm having a problem getting the binding to the popup details view user control to work right. If I step through the code, it executes fine, but the browser throws the following error:

    Sys.InvalidOperationException: ManagedRuntimeError #4002 in control 'Xaml1'. System.Exception: Catastrophic failure (Exception from ....

    ...the error mentions "MS.Internal.XcpImports.ConvertStringToTypedCValue" and "MS.Internal.SilverlightTypeConverter.ConvertFrom(Object value)"

    The web browser goes completely blank and it seems that my Silverlight app has disappeared. If I take all controls with bindings to my story object out, the popup works fine (well, except for one small thing, mentioned below)...but even adding in one control with a binding will generate this error. Anyone have any ideas? The error seems to be saying that it doesn't know how to handle the type it's being bound to. Did I miss something?


    Also, I can't get the Opacity to work right for the semi-transparent grey background of the popup. No matter what value I set it to (even "0.0"), it's just a solid grey. I double-checked my spelling of the attribute several times, and it's spelled right. I'm running XP...not Vista, does that make a difference? If semi-transparent panels only works in Vista, that would really suck.

  • Is it my old machine or does the XAML previewer go off from time to time. While entering the code for the StoryDetailsView.xaml, the Page.xaml preview disappeared...

    Is this a bug in the xaml viewer or I am doing somehting wrong?

  • cmptr_man re: opacity bug

    I had the same issue - until ... hehe

    Make sure you remove the default background color that is assigned to the Grid you're using in the user control. For me it defaulted to "Background=White" ... once I removed that the opacity worked like a charm!

  • Hello,

    I have the same issue than cmptr_man(Wednesday, March 12, 2008 3:31 PM) regarding the blank web browser page when displaying the detail page. I also noticed that it is linked to the binding feature, but didn't find yet why. On the Scott's project it works fine and didn't identify the gap between his and my project !

    If somebody could help me (us), it would be great !

    Thanks in advance,

    Paul

  • cmptr_man re: blank web page

    Ok i fixed my bug, hoping it will solve yours.

    In DiggStory class declaration, ensure that HrefLink is Uri type "public Uri HrefLink { get; set; }". Then in DisplayStories function, use this sentence "HrefLink =new Uri((string)story.Attribute("link")),".

    Hope this will help you,

    Paul

  • I was trying to show Master/detail NorthWind db Customers/Orders, using DataGrid. Is it possible to use DataGrid.RowDetailsTemplate to show related record?

  • I'm unable to get the digg:storydetailsview.........so please tell me whether I'm missing anything. pls send me the reply in manikandan.venkataraman@wipro.com

Comments have been disabled for this content.