12 Days of RIA – Day 5 – Read Only Data

Opening Artists.xaml, I’d like to make it so I can search for an artist, and then see all their associated albums and tracks. This is a simple 3-level hierarchy as evident in the data model and the object model created from it. Accordingly, I’d like to start with this by adding 3 data grids to view before doing any styling work. I first did a little refactoring of the layout on this page, wrapping the StackPanel that holds the 2 TextBlocks into a Grid. VS2010 now has a nice interface for editing the Grid’s RowDefinitions collection, so I used it to add 4 rows (one for the StackPanel, three for the data grids) as shown:

image

Connecting it to the Artists was pretty easy. I just navigated to the Data Sources tab (choose Data | Show Data Sources from the menu if you don’t see it.) I simply dragged Artist from the TwelveDaysOfRiaContext and dropped it on the Grid, and then Reset Layout|All and set Grid.Row=1 and reset Grid.RowSpan until I had this:

image 

When I ran the app and navigated to the Artists view, I got the following:

image

which is the full list of Artists in Artist ID order and probably not the desired effect (remember the advice of the comment blocks above the GetXxx methods in the TwelveDaysOfRiaService class.) The designer in VS2010 is quite smart though, and it enables the addition of parameterized methods that return IQueryable<Xxx> which are discoverable by the client side. Even better, if the parameters are simple enough, the designer can generate the UI Elements to input them and invoke the method.

To demonstrate, I started by adding a method to get Artists by name as shown:

image

I then connected the client to this query by first rebuilding (rebuilding between steps often is a good idea when developing an app on RIA Services.) I knew that the front end could see my query because it was now available from the Data Source tab under the Artist entity.

image

I removed the DataGrid and its associated DomainDataSource from the XAML (these were added when I dropped the Artist entity on the design surface previously.)

image

I then selected the GetArtistsByNameQuery and dropped Artist on the Grid again. I needed to do a little editing of the XAML to get the layout to look nice, but came up with this.

image

The XAML in this file warrants a closer look. The DomainDataSource is where the GetArtistsByNameQuery is bound to the view.

<riaControls:DomainDataSource

    AutoLoad="False"

    Height="0"

    LoadedData="artistDomainDataSource_LoadedData_2"

    Name="artistDomainDataSource"

    QueryName="GetArtistsByNameQuery" Width="0">

     <riaControls:DomainDataSource.DomainContext>

        <my:TwelveDaysOfRiaContext />

     </riaControls:DomainDataSource.DomainContext>

     <riaControls:DomainDataSource.QueryParameters>

     <riaControls:ControlParameter

          ControlName="nameStartsWithTextBox"

          ParameterName="nameStartsWith"

          PropertyName="Text" />

     </riaControls:DomainDataSource.QueryParameters>

</riaControls:DomainDataSource>

It found the parameters for the query, and bound them to corresponding UIElements. Notice that its AutoLoad property is set to False – the prevents the query from executing when the frame navigates to Artists.xaml. The StackPanel contains the UIElements into which the query parameters are entered.

<StackPanel Orientation="Horizontal">

   <dataInput:Label Content="Name Starts With:"

        Margin="3" VerticalAlignment="Center" />

    <TextBox Name="nameStartsWithTextBox" Width="60" />

    <Button Click="artistDomainDataSourceLoadButton_Click"

         Content="Load" Margin="3" Name="artistDomainDataSourceLoadButton" />

</StackPanel>

And finally, the DataGrid is bound to the artistDomainDataSource as shown.

<data:DataGrid Grid.Row="1" AutoGenerateColumns="False"

               ItemsSource="{Binding ElementName=artistDomainDataSource,

               Path=Data}"

               Name="artistDataGrid"

                RowDetailsVisibilityMode="VisibleWhenSelected">

       <!-- etc. -->

</data:DataGrid>

All this yields an app which provides a lookup of artists by name:

image

image

This is great, but Artists also have Albums – it would be nice see those once an Artists has been selected. I dragged the Albums from under the Artist onto the design surface and reset the layout properties, which yielded the following:

image

The designer picked up that I wanted a DataGrid bound to Artist entities, but it didn’t make the expected connection at run time. To fix that, I bound the second DataGrid to the SelectedItem of the first via element binding.

image

I manually changed the path to SelectedItem.Albums, but the Albums didn’t show up as expected. The solution to this is to set the Include() attribute on the Albums property of the Artist entity on the server side as shown:

image

and to add an Include to the LINQ query in the domain service

image

This yielded the desired effect.

image

Repeating the process for Tracks with the tweak shown below to the Include in the LINQ query…

image

…got me to a full master-details-details view…

image

…and there was much rejoicing!  Code for the 5th day is here.