Silverlight 4 + RIA Services - Ready for Business: Consuming Data in the Silverlight Client

To continue our series, let’s see where the fun comes in my look at how easy that is to consume from the client.  First just to help you understand what is happening behind the covers, let’s look at a code-behind solution.  In View\Home.xaml put a simple DataGrid on the form.

  <sdk:DataGrid Name="dataGrid1" Height="152" Width="692" />

Then add these lines of code to Home.xaml.cs

 

   1: var context = new DishViewDomainContext();
  2: this.dataGrid1.ItemsSource = context.Restaurants;
  3: 
  4: context.Load(context.GetRestaurantsQuery());
  5: 

 

In line 1, we create a DishViewDomainContext… notice this is the automatically generated (via an MSBuild task) from the DishViewDomainService on the server. 

In line 2, Notice we have a Restaurants property – we provide this because there is at least one query method that returns restaurants.  Notice the cool binding magic, we have not yet populated this data from the server, but we go ahead and bind it.  This avoids any kind of complex callback logic. 

In line 4, we explicitly load the data.. this is the network call, so we want to make sure it is clear to the developer when this happening.   As an argument we pass exactly which query method (and any arguments) to use.

Now we run it and we get our data..

image_thumb[20]

Very painless, but it gets even easier ;-)

Go and in delete this code and the Xaml..  Then notice the DataSources window

image_thumb[80]

image_thumb[22]

Notice this is simply a visual representation of exactly what we were doing in code.

image_thumb[23]

Notice i can change what default UI to generate and which query method to use.

 

Dragging Restaurants to the form and bingo, we have our data.

image_thumb[26]

 

Run it and we have our data… what could be easier?

image_thumb[28]

Click on the column headers – notice sorting works!  There is no code you had to write on the client or server to enable it.  This just comes for free out of returning an IQuerable. 

Now let’s add paging..

First we drag and drop the DataPager control to the form, then do a bit of layout and we end up with something that looks nice

image_thumb[29]

But we still need to wireup the DataPager to the same underlying DataSource.  This is easy enough done by draging and dropping the same Restaurant element from the DataSources window to the DataPager.  You will now you did this right if the DataPager becomes enabled. 

image_thumb[32]

 

image_thumb[34]

 

Notice that paging works great!  No code needed on the client or the server, again, all done through using that simple Linq query we wrote on the server. But what about paging AND sorting… do they work well together?  Will it just sort the page of data that is loaded locally?  The answer of course is that sorting and paging compose nicely together and the sort is actually sent all the way to the data tier and executed there in a very efficient way.

 

Now let’s add filtering.  With just a bit more work in the UI, we can add a way to filter by postal code.

 <sdk:Label Name="label1" Content="Postal Code:" FontSize="14" Margin="0,0,462,13" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="110,12,0,0" Name="postalCodeTextbox" VerticalAlignment="Top" Width="120" />

image_thumb[36]

Then we need to wire this up to the query.  Of course we want the filter applied as close to the data as possible.  We don’t want to download all the entities locally, then filter, nor do we want to pull them all to the middle-tier and then filter.  What we want is for the filter to be applied at the database level.  Luckily this is very easy to do with LINQ composition. 

First we select the DomainDataSource in the Document Outline view.

image_thumb[37]

 

image_thumb[38]

image_thumb[40]

Operator – typically you should set this to “Contains”.  If you use the default of “IsEqualTo” the first load (when there is no filter) will result in no results returned. 
PropertyPath – this is the property on the entity that you are filtering on… Just type in the simple name. 
Value – this is where to get the value to compare from.  It is easiest to do UI-to-UI binding to the TextBox’s Text property.

image_thumb[42]

Here is the dialog once we are done:

image_thumb[44]

And the resulting Xaml:

         <riaControls:DomainDataSource Name="restaurantDomainDataSource" AutoLoad="True" 
                                      d:DesignData="{d:DesignInstance my:Restaurant, 
                                                     CreateList=true}" 
                                      Height="0"  Width="0" 
                                      LoadedData="restaurantDomainDataSource_LoadedData_1" 
                                      QueryName="GetRestaurantsQuery">
            <riaControls:DomainDataSource.FilterDescriptors>
                <riaControls:FilterDescriptor Operator="Contains" 
                                              PropertyPath="PostalCode" 
                                              Value="{Binding ElementName=postalCodeTextbox, Path=Text}" />
            </riaControls:DomainDataSource.FilterDescriptors>
            <riaControls:DomainDataSource.DomainContext>
                <my:DishViewDomainContext />
            </riaControls:DomainDataSource.DomainContext>
        </riaControls:DomainDataSource>

image_thumb[47] 

Notice no code changes at all, and no changes to the business logic in the DomainService in particular.