Exercise 2: Editing Events

In this part, you will add a new page to the Silverlight application for editing the details of an event. This will illustrate how the domain service we created in the previous part provides the ability to fetch data selectively and to push back changes to the server after the user has edited the data.

Create the Events Details Page

  1. In the SlEventManager project, right-click on the Views folder and choose to Add a New Item.
  2. Select the Silverlight Page template.
  3. Name the new page EditEvent.
  4. Click Add.
  5. Open the Data Sources window.
  6. Find the same Event entity item you added to the Home page in the previous part of this lab and select it.
  7. Click on the dropdown button for the Event entity.
    Note:
    This lets you choose what sort of UI element or elements will appear when you drag the item onto the design surface. By default, a collection of entities such as this will produce a DataGrid, but the menu offers an alternative, Details.
  8. Select Details.

    Figure 8

    Changing the Layout to Details

  9. Drag the Event entity onto the new XAML page.

    Note:
    This time, instead of a DataGrid, you should see a set of editable text fields, date pickers, and a checkbox to represent textual, date, and boolean values respectively:

    Figure 9

  10. Laying out the Details
    Note:
    If you inspect the XAML, you’ll see that once again, Visual Studio has added a DomainDataSource non-visual control to the page, which it has configured in exactly the same way as it did in the previous part. This would make sense if we were writing a master/details view, where the fields edited the currently-selected item in some list. But that’s not how this UI will work: this page will show a single event. (It will eventually also use a master/details style, but that will be for managing the tracks and sessions. To do that for all the events as well would be overkill.) So we need to do some work to get the domain data source to pick just a single value. But how will it know which event it’s supposed to edit? We’ll put this into the URL so an event administrator can bookmark the page for editing a particular event. We’ll have a URL of the form: https://sitename/SlEventManagerTestPage.aspx#/EditEvent?EventID=3

    Right now, there’s no way to get to this new page, so we’ll start by adding a button to the Home.xaml page to edit the currently selected event. We’ll make that navigate to this new page, putting the event ID into the URL query string.

Setting up the Navigation Parameter

  1. Open the Home.xaml.cs(C#) or Home.xaml.vb(VB) codebehind file.
  2. Add the following helper function, which will help us navigate to EditEvent:

    C#

    private void NavigateToEditEvent(int eventId) { NavigationService.Navigate(new Uri("/EditEvent?EventID=" + eventId, UriKind.Relative)); }

    Visual Basic

    Private Sub NavigateToEditEvent(ByVal eventId As Integer) NavigationService.Navigate(New Uri("/EditEvent?EventID=" & eventId, UriKind.Relative)) End Sub
  3. Add the following using declaration for this to compile:

    C#

    using System;

    Visual Basic

    Imports System
    Note:
    This method builds a URL with the event ID in the query string, and navigates to the event editing page. (We will eventually need to perform this step in a couple of different places, which is why we’re putting it in a helper function.)
  4. Go back to the Home.xaml page in Visual Studio.
  5. Make some extra space at the top of the page by dragging the top of the data grid down a bit.
  6. Add a grid row by clicking in the blue bar to the left of the design surface:

    Figure 10

    Adding a Grid Row

  7. After the closing tag for the DataGrid, but before the closing </Grid> tag, add the following XAML:

    XAML

    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> <Button x:Name="editCurrentButton" Content="Edit current event" /> </StackPanel>
  8. In the Grid.RowDefinitions section near the top of the file (which was added when you created the extra row), modify the Height of the first row to Auto.
  9. Double click on the Edit current event button in the design view. This generates and displays the button’s Click event handler.
  10. Add the code shown below to the Click hander:

    C#

    private void editCurrentButton_Click(object sender, System.Windows.RoutedEventArgs e) { Event currentEvent = eventDataGrid.SelectedItem as Event; if (currentEvent != null) { NavigateToEditEvent(currentEvent.EventID); } }

    Visual Basic

    Private Sub editCurrentButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles editCurrentButton.Click Dim currentEvent As [Event] = TryCast(eventDataGrid.SelectedItem, [Event]) If currentEvent IsNot Nothing Then NavigateToEditEvent(currentEvent.EventID) End If End Sub
    Note:
    The Event type that this refers to comes from the domain service you added earlier. The WCF RIA Services link feature of Visual Studio generates client-side classes that correspond to the entities exposed by the service. However, it generates these in a separate namespace, so the code above won’t compile.
  11. Add the following using declaration to the top of the codebehind file:

    C#

    using SlEventManager.Web;

    Visual Basic

    Imports SlEventManager.Web
  12. We should only enable the button when the user has selected an item (an Event) in the DataGrid. Go to the XAML, find the button and set its IsEnabled property to false.
  13. Double click on the DataGrid. This will add a SelectionChanged event handler.
  14. Add the code shown in this SelectionChanged handler:

    C#

    private void eventDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { editCurrentButton.IsEnabled = eventDataGrid.SelectedItem != null; }

    Visual Basic

    Private Sub EventDataGrid_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles EventDataGrid.SelectionChanged editCurrentButton.IsEnabled = EventDataGrid.SelectedItem IsNot Nothing End Sub
  15. Run the application.
  16. Select an event in the grid
  17. Click the Edit current event button.
    Note:
    The application should navigate to the event editing page, and you’ll see the ID of the item you selected in the URL. However, the editing page is currently ignoring this ID completely. It will just edit the first event that comes back from the service every time.
  18. Close the web browser.

Filtering the Domain Data Source

  1. Go to the EditEvent.xaml.cs(C#) or EditEvent.xaml.vb(VB) page. Visual Studio will have added an OnNavigatedTo method that gets called when the user navigates to this page.
  2. Implement the OnNavigatedTo method as shown:

    C#

    protected override void OnNavigatedTo(NavigationEventArgs e) { string eventId = NavigationContext.QueryString["EventID"]; eventDomainDataSource.FilterDescriptors.Add( new FilterDescriptor { PropertyPath = "EventID", Operator = FilterOperator.IsEqualTo, Value = eventId }); }

    Visual Basic

    Protected Overrides Sub OnNavigatedTo(ByVal e As NavigationEventArgs) Dim eventId As String = NavigationContext.QueryString("EventID") eventDomainDataSource.FilterDescriptors.Add(New FilterDescriptor With {.PropertyPath = "EventID", .Operator = FilterOperator.IsEqualTo, .Value = eventId}) End Sub
    Note:
    This retrieves the EventID from the URL. It then adds a filter descriptor collection to the DomainDataSource non-visual control telling it to filter events by an exact match on the EventID property.
  3. Run the application.
  4. Select an event in the DataGrid.
  5. Click the Edit current event button. This time, the event editing page will show the details for the item you have selected, rather than the first item.
    Note:
    Although we specified the filter criteria on the client, the filtering is in fact taking place on the server, thanks to the “composability” feature of WCF RIA Services. When a domain service operation returns an IQueryable<T>, WCF RIA Services allows clients to pass in optional filter, sorting, and grouping criteria as part of the request. These criteria are then applied to the IQueryable<T> that the domain service operation returns, using the standard LINQ query operators for filtering, sorting, and grouping.

    Since our domain services returns IQueryable<T> directly from the Entity Framework, this means that filtering, sorting, and grouping are done by the Entity Framework. And the Entity Framework implements these standard LINQ operators in the database. So in this example, the client-side filter specification is ultimately implemented as a WHERE clause in the SQL query executed against the database.
  6. Stop the application.

Allow Saving of Events

  1. In EditEvent.xaml, drag a button on from the Toolbox. (You can open the Toolbox from the View menu.)
    Note:
    While the user can edit the event details, these edits remain on the client side. RIA Services will not push changes back to the database unless asked, because it has no way of knowing when it should do that. We need to add some code to make that happen.
  2. Set the button’s Name to saveChangesButton
  3. Set the button’s Content to Save Changes.
  4. Double click the button to generate the Click handler.
  5. Add just one line of code to the Click event handler:

    C#

    private void saveChangesButton_Click(object sender, RoutedEventArgs e) { eventDomainDataSource.SubmitChanges(); }

    Visual Basic

    Private Sub saveChangesButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles saveChangesButton.Click EventDomainDataSource.SubmitChanges() End Sub
    Note:
    This SubmitChanges method builds a message describing all of the properties that have changed since the entities were fetched from the services. (The client-side entity objects that WCF RIA Services generates all perform change tracking to enable this.) It sends this message to the server where the server-side parts of RIA Services will start up a transaction, and then call all the methods on your domain service needed to perform all of the updates.

    So as far as network communications are concerned, updates happen as a single operation, but this batching is done for you. Your domain service just provides the individual insert, update, and delete operations and RIA Services will call what it needs to call to process the batched update. (The relevant insert, update, and delete operations were generated when you added the domain service, because you checked the Enable editing checkboxes.)
  6. Run the application again.
  7. Pick an event to edit and click the Edit current event button.
  8. Change a couple of the properties.
  9. Click Save Changes.
  10. Click the Home link at the top left to go back to the home page with the event list. This will reload the data, so you should now be able to see the changes you made in the list.

Conclusion

The functionality you just added wasn’t technically necessary to add this new page. The DataGrid is editable by default. It does two-way binding to the source objects, and you can double click on grid cells to edit them. So we could have added a button to save changes on the original form, using the same SubmitChanges method. However, in general it’s common to have more selective pages, such as the single event editing page added in this part. When we add features later in this lab to edit track and session information, there will be more data to show per event, and having all of the events be editable from a single page would involve fetching a rather large quantity of data up front. (We’d be not far away from having the client download a complete copy of the database on startup. That might work for the small volumes of data we’re working with in this example, but it’s clearly not a sustainable approach for a real application.)