Drilling Down on a Record

Summary lists are generally used as a means to find and drill down on a record to get more details and/or edit the record. There are a number of approaches you can take to implement this type of behavior, including the following”

  • Navigating to a details view
  • Opening the details in a pop-up window
  • Using the row details feature of the DataGrid to display the details
  • Using a master/details view

Which approach you choose really depends on the workflow you are implementing. Each has its own pros and cons, and your choice will largely depend upon the user experience design for your application. In this section, we will take a look at each of these approaches and how to implement them.

Navigating to the Details View

One simple way of displaying the details of a given item is to simply create a details view, and navigate to it using the Navigation Framework. How you can initiate this behavior isn't particularly straightforward, however. You have probably implemented this type of behavior in the past by having the user double-click an item in the list, but there are no DoubleClick events in Silverlight. In fact, there's no RowClick event on the DataGrid either, nor is there an ItemClick event on the ListBox. So how can you enable the user to drill down on a record? Let's take a look at some approaches you might like to take.

images Note If you still want to use a double-click behavior, you can implement it yourself using a behavior or a trigger. You can also find various double-click behaviors and triggers already created by other developers with a quick search on the Web. Behaviors are covered in Chapter 10.

If you are using a DataGrid, then you can use a template column and add a control such as a Button or HyperlinkButton to it that the user can click to navigate to the details view. Alternatively, if you are using a ListBox, then you can simply include one of these controls in your item template.

Unfortunately, the Navigation Framework doesn't allow you to pass complex objects between views. Therefore, in order to enable the details view to know which record it should load and display, you will need to pass a unique identifier to that view as a query string parameter. You could use the HyperlinkButton control, which can be configured to automatically navigate to the details view with no code required; however, it unfortunately does not have the ability to automatically include the unique identifier of the record as a parameter in the URI to navigate to the details view. Your options in this case are to either handle the HyperlinkButton's Click event in the code-behind and build the URI to navigate to manually prior to initiating the navigation, or to bind the NavigateUri property of the HyperlinkButton to the property representing the unique identifier on the bound object and use a value converter to build the full URI. The value converter approach is probably the most appropriate choice, especially if you are using the MVVM design pattern; however, it does not apply if you are using a Button control, because the Button control has no NavigateUri property. Therefore, we'll focus on the code-behind approach here instead, which you can use with either a HyperlinkButton control or a Button control.

The following XAML demonstrates the definition of a HyperlinkButton control, which can be added to the cell template of a DataGrid template column or to a ListBox item template, that displays the name of the product as its text, has a Click event handler, and binds the whole ProductSummary object to its Tag property, which it does by assigning {Binding} to its property value, as follows:

<HyperlinkButton Content="{Binding Name}" Tag="{Binding}"
                 Click="NameButton_Click" />

Now, in the Click event handler for the HyperlinkButton, we can get the HyperlinkButton that raised the event, which is passed into the event handler as the sender parameter, and then get the ProductSummary object corresponding to its summary list item/row from its Tag property. The structure of this URI will depend on how your URI mapping has been configured. (See Chapter 3 for more information on URI mapping.) The following example demonstrates building a URI that navigates to the product details view, and passes it the ID of the product to display, which it can obtain from the query string and retrieve the corresponding details from the server for.

private void NameButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
    HyperlinkButton button = sender as HyperlinkButton;
    ProductSummary productSummary = button.Tag as ProductSummary;

    Uri detailsUri = new Uri("ProductDetails/" + productSummary.ID.ToString(),
                             UriKind.Relative);
    NavigationService.Navigate(detailsUri);
}

images Note You should also handle the KeyDown event of the control to capture the Enter key being pressed, and navigating to the details view corresponding to the selected item/row. This helps enable users to use the keyboard to navigate around the application instead of having to switch between using the keyboard and the mouse.

Opening Details in a Pop-Up Window

Silverlight has a neat class built in called ChildWindow that enables you to display a modal pop-up window with content that you define. This makes it perfect for use in scenarios in which you want the user to be able to select a record in a summary list and display the related details in a pop-up window.

To implement a child window, add a new item to your project and select the Silverlight Child Window item template from the dialog. This will create a new XAML file (and corresponding code-behind class) inheriting from the ChildWindow class. As shown in Figure 6-11, you have a nice window-type layout that you can style to suit your user interface design if necessary, already set up with OK/Cancel buttons, which you can add your own control layout to so that the user can view and edit the details of the selected record in the summary list.

images

Figure 6-11. A ChildWindow in design mode

After you have defined the layout of the child window, you need to be able to display it when the user clicks a record in the summary list. Using the approaches described in the previous section, instead of navigating to a new view you can simply handle the Click event of the hyperlink or button defined for an item/row and display the child window. All that is required to display a child window is to instantiate the class and call the Show method, like so:

ProductDetailsWindow window = new ProductDetailsWindow();
window.Show();

images Note While the child window is displayed modally, unlike displaying modal windows in Windows Forms or WPF, the method returns immediately, instead of waiting for the window to be closed. If you need to perform an action, such as updating the summary list, after the window is closed, you will need to handle either the Closing or Closed event of the child window and put your logic to do so in there.

The modality of the child window is provided by applying a semitransparent Rectangle control overlaying the application's user interface, positioning the child window control on top of this, and disabling the root visual. Therefore, any mouse clicks outside the child window will be ignored, effectively providing a modal behavior.

The source code for the ChildWindow class can be found in the Silverlight Toolkit, so you can modify this modal behavior by modifying the source code if you wish. With slight modifications to the code, you can enable multiple child windows to be displayed simultaneously. Microsoft Silverlight program manager Tim Heuer has actually already done this with a control called the FloatableWindow, which includes additional behavior such as the ability for it to be resized by the user. It is available on CodePlex at http://floatablewindow.codeplex.com.

However, in this scenario, where we want to show the details of the selected record in the summary list, we need to pass in an identifier or an object so that it knows what data to load and display. Unlike the previous approach to navigating to a new view where we could only pass a simple string to the new view to tell it which record to load, we can actually pass complex objects into a child window by modifying the constructor of the class to accept a simple type or object with the required details as a parameter. For example, change the constructor, as follows:

public ProductDetailsWindow(ProductSummary productSummary)
{
    InitializeComponent();

    // Logic to load product data corresponding to
    // the passed-in productSummary object can go here
}

You can now pass it the selected object in the summary list when instantiating the window, like so:

HyperlinkButton button = sender as HyperlinkButton;
ProductSummary productSummary = button.Tag as ProductSummary;

ProductDetailsWindow window = new ProductDetailsWindow(productSummary);
window.Show();

Figure 6-12 demonstrates displaying the details of a product in a child window.

images

Figure 6-12. Product details in a child window

Displaying Details Using the DataGrid's Row Details

The row details feature in the DataGrid enables you to display additional data related to a row in the DataGrid—useful when you only want to show limited details from the bound object in the main row, and display additional details in an area below it, as demonstrated in Figure 6-13. This is especially useful when you want to show additional details about a row without displaying those details in a pop-up window or navigating away from the summary list view.

images

Figure 6-13. Row details in a DataGrid control

This is achieved by assigning a data template defining the layout of the row details area to the RowDetailsTemplate property of the DataGrid. For example:

<sdk:DataGrid>
    <sdk:DataGrid.RowDetailsTemplate>
        <DataTemplate>
            <!-- Row details layout goes here -->
        </DataTemplate>
    </sdk:DataGrid.RowDetailsTemplate>
</sdk:DataGrid>

You can assign a value to the RowDetailsVisibilityMode property to specify whether the row details are displayed only when the row is selected (VisibleWhenSelected), displayed for every row in the DataGrid (Visible), or never displayed (Collapsed). You can use the RowDetailsVisibilityChanged event to handle when the row details are shown/hidden, enabling you to implement behaviors such as loading related data from the server into the row details when the row is selected and the row details section is displayed.

By default, if the DataGrid has columns extending beyond the width of the DataGrid, its horizontal scrolling functionality will also allow horizontal scrolling of the row details area. However, you can freeze the row details so that they remain fixed in position regardless of any horizontal scrolling motion by setting the AreRowDetailsFrozen property to True.

Implementing a Master/Details View

The master/details view is a relatively common user interface pattern in which the summary list (acting as the master) occupies one part of the view, and when the user selects an item from the list, the complete record (acting as the details) are displayed in another part of the view for editing. For example, you might have a list of products (i.e., the master), and when the user selects a product from this list, details of the selected product will be displayed in a data entry form in another part of the view, where they can be edited.

This is actually quite easy to implement, thanks to the synchronization behavior provided by collection views, with no code actually required. Let's say you are using a DomainDataSource control in your view that retrieves the list of products and displays them in a list, using either a DataGrid or a ListBox bound to the DomainDataSource control. We'll simply bind a TextBox in a manner to display the name of the selected product in the list and enable you to edit it.

  1. Add a TextBlock control to your view and bind its DataContext property to the DomainDataSource's Data property (as the DataGrid/ListBox does).
  2. Now bind its Text property to the Name property of the bound object, like so:
    <TextBlock DataContext="{Binding ElementName=productSummaryDDS, Path=Data}"
               Text="{Binding Name}" />

Now run your project. When you select a product in the list, note how the text in the TextBlock automatically changes to display the corresponding name of that product. Considering that the TextBlock isn't even bound to the list, how does it know what item has been selected? This is because the DomainDataSource control returns a DomainDataSourceView from its Data property, which the TextBox control is binding to. In addition to filtering/sorting/grouping functions, which are enabled without the underlying collection needing to be modified, collection views also implement current record management functions, including properties such as CurrentItem and CurrentPosition, and methods such as MoveCurrentToNext and MoveCurrentToPosition. When a property on a control that accepts a value (rather than a collection) is bound to a collection view, the data binding engine will recognize that the binding source is a collection view and will assume that you don't actually want to bind to the collection view itself. It, therefore, drills down to the collection view's CurrentItem property and binds to the given property on that instead.

images Note Optionally, you can use "{Binding CurrentItem.Name}" as the binding expression instead, with exactly the same results, but explicitly drilling down to the CurrentItem property on the collection view isn't necessary unless you have a property on the object you want to bind to that has the same name as a property on the collection view object, such as Count.

When you click on a new product in the list, the list will automatically update the CurrentItem property on the collection view that it's bound to and set it to that of the selected item. In other words, by default, list controls automatically synchronize the CurrentItem property of the collection view to which they are bound with their selected item. When the CurrentItem property of the collection view is changed, any other controls in the view that are bound to it will have their binding source changed accordingly. The effect of this behavior is that those controls will display the details of the currently selected item in the list, effectively providing a master/details type behavior that your application can leverage.

images Note Although most of the time you will want this synchronization behavior, sometimes you might want to have more control over the process. You will find that some of these controls, such as the ListBox control, have an IsSynchronizedWithCurrentItem property whose default value is null. You can't actually set this property to true (it will throw an exception if you try), as it depends on whether or not the binding source is a collection view for whether synchronization with the current item is possible. If the binding source is a collection view, current item synchronization will automatically be turned on, although you can explicitly turn it off if you want by setting the property to false. If you do so, you can control what item is the current item in the collection view manually (in code), using the record navigation methods (such as MoveCurrentToNext and MoveCurrentToPosition).

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

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