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:
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:
When I ran the app and navigated to the Artists view, I got the following:
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:
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.
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.)
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.
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:
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:
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.
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:
and to add an Include to the LINQ query in the domain service
This yielded the desired effect.
Repeating the process for Tracks with the tweak shown below to the Include in the LINQ query…
…got me to a full master-details-details view…
…and there was much rejoicing! Code for the 5th day is here.