RIA: Data Source Control - Jesse Liberty - Silverlight Geek Page view counter

RIA: Data Source Control

MiniTutorialLogo
ProjectTuringLogo Turing Project Page: [Novice: 11 | Advanced: 8 ]
FAQ | Table of Contents | Definitions
What is this and where do I start?

Part 3 of 3

This is the last of a three part sub-series on using Entity Frameworks and RIA Data Services to move data from our Sql Server database to our Silverlight Application’s DataGrid.

In Part 2, we explored returning an object graph by using the Entity Frameworks and by decorating the metadata for the RIA Services with the properties we wanted to retrieve from the contained object.

Until now, however, all of our code has instantiated via RIA Services context programmatically, invoked the query function programmatically, and assign the returned collection to the items source property of the data grid programmatically. In this post, I’ll look at a declarative approach.

Using the RIA Services DomainDataSource Control

We’ll begin with the program as we left it after the previous blog post, but we’ll immediately remove the three lines in blogs.xaml.cs that manipulates the data context.

   1: public partial class Blogs : Page
   2: {
   3:     //  private readonly BlogsContext bc = new BlogsContext();
   4:   public Blogs()
   5:   {
   6:     InitializeComponent();
   7:     //    bc.Load( bc.GetBlogsQuery() );
   8:     //    this.blogsDataGrid.ItemsSource = bc.Blogs;
   9:   }

Having removed the programmatic interface to the data context, let's now open up blogs.xaml  and provide it with information about the data context by way of teh DomainDataSource  control, which we must first add to the toolbox. To do so, right-click on the Silverlight Xaml Controls tab, and then click on Choose Items.

Within the Choose Toolbox Items dialog box click on the Silverlight Components tab, and then click the browse button. Navigate to your program files ->Microsoft SDKs -> RIA Services, pick the folder for the latest version, within that:  Libraries-> Silverlight.  Double-click on System.Windows.RIA Controls.dll 

You should find that the DomainDataSource control has been added to the bottom of your list of controls; you may want to right-click and choose to sort them alphabetically.

Drag a DomainDataSource control onto the Xaml page just above the DataGrid.  By dragging it on rather than writing it yourself Visual Studio will create the namespace for you set up your using statement and your references.

The four attributes you'll typically want to set, if no others, are the Name , LoadSize, QueryName, and the AutoLoad property. We will examine each of these in turn below.

You will also want to set the domain context property which you will do it explicitly as shown in the code that follows:

   1: <riaControls:DomainDataSource x:Name="BlogsDataSource"
   2:                               LoadSize="15"
   3:                               QueryName="GetBlogs"
   4:                               AutoLoad="True">
   5:    <riaControls:DomainDataSource.DomainContext>
   6:       <ds:BlogsContext />
   7:    </riaControls:DomainDataSource.DomainContext>
   8: </riaControls:DomainDataSource>

 

The LoadSize property instructs the DomainDataSource control as to how many records to get for each query to the database.  This allows you to fine tune the performance of your application (too small load size, and you are making many calls to the database, to larg a load size and there will be a noticeable wait for the data to arrive).

The QueryName parameter references the query We created in the RIA Services class, you will remember setting GetBlogs to include bloggers. Notice that here you use the name of the method (GetBlogs ).  Rather than "GetBlogsQuery()" as you did in C#.

Setting Autoload to true tells the DomainDataSource control to load the first set of data when it is initialized.

Note that the namespace for BlogsContext is DS as opposed to RIAControls the namespace for the DomainDataSource.  DS is a namespace that refers to the Web project (you’ll need to add that to the top of the file)

Build and run the application.  The results, that is the running application, are identical to what you had before.  However now you are not creating this programmatically but rather declaratively in the Xaml.

Sorting

Is relatively straightforward to add sorting declaratively as well. You do so by adding a sort descriptor to your DomainDataSource control.  In the case shown below (Lines 9 through 11), we are setting the SortDescriptor property explicitly, and having it sort on BlogName.

 
   1: <riaControls:DomainDataSource x:Name="BlogsDataSource"
   2:                               LoadSize="20"
   3:                               QueryName="GetBlogs"
   4:                               AutoLoad="true">
   5:    <riaControls:DomainDataSource.DomainContext>
   6:       <ds:BlogsContext />
   7:    </riaControls:DomainDataSource.DomainContext>
   8:    <riaControls:DomainDataSource.SortDescriptors>
   9:       <riaData:SortDescriptor PropertyPath="BlogName"
  10:                               Direction="Ascending" />
  11:    </riaControls:DomainDataSource.SortDescriptors>
  12: </riaControls:DomainDataSource>

Sending the sort column in this way it causes the data grid to open with that column sorted.  The user, of course, can sort on any column by clicking on the column header.

Filtering

Before we leave the DomainDataSource control, let's take a quick look at filtering, which works much like sorting. Sorting the grid In this case rather than explicitly putting into our filter what it is we are filtering on, we will instead set the "Control Parameter" to point to another control on the same page that will provide the text on which to sort.

To begin, we'll add a text box into which the user can type the desired filter.

<StackPanel Orientation="Horizontal"
            HorizontalAlignment="Right"
            Margin="0,-16,0,0">
   <TextBlock VerticalAlignment="Center"
              Text="Name Contains Filter" />
   <TextBox x:Name="filterText"
            Width="75"
            FontSize="11"
            Margin="4"
            Text="Silverlight" />
</StackPanel>

 

This code can be placed directly above the DomainDataSource, and as you can see it provides a textblock with a prompt and a text box, which will gather in the desired filter. Next We'll add a FilterDescriptors element to the DomainDataSource control, and tell it to get its value from that text box:

   1: <riaControls:DomainDataSource x:Name="BlogsDataSource"
   2:                               LoadSize="20"
   3:                               QueryName="GetBlogs"
   4:                               AutoLoad="true">
   5:    <riaControls:DomainDataSource.DomainContext>
   6:       <ds:BlogsContext />
   7:    </riaControls:DomainDataSource.DomainContext>
   8:    <riaControls:DomainDataSource.SortDescriptors>
   9:       <riaData:SortDescriptor PropertyPath="BlogName"
  10:                               Direction="Ascending" />
  11:    </riaControls:DomainDataSource.SortDescriptors>
  12:    <riaControls:DomainDataSource.FilterDescriptors>
  13:       <riaData:FilterDescriptorCollection>
  14:          <riaData:FilterDescriptor PropertyPath="BlogName"
  15:                                    Operator="Contains">
  16:             <riaData:ControlParameter ControlName="filterText"
  17:                                       PropertyName="Text"
  18:                                       RefreshEventName="TextChanged" />
  19:          </riaData:FilterDescriptor>
  20:       </riaData:FilterDescriptorCollection>
  21:    </riaControls:DomainDataSource.FilterDescriptors>
  22: </riaControls:DomainDataSource>

 

The filter descriptors begin online 12 and run through line 21.  Notice on lines 14 and 15 that you are indicating which property is being filtered on and that you have your choice of operators such as contains, is, etc.  On lines 16 through 18, you indicate the name of the control that has the filter, the name of the property of the control from which to extract the filter, and the event on which you will update the filter.

N.B.: the code is showing updates each time a letter is typed in the text box.  This will cause a call to the database for every letter that's typed.  You can solve this by using the Load Delay parameter.  Of course having a low delay will make the page initially load more slowly, so you may want to add the load delay programmatically after you initialize the page.

 

Finally to give it a bit of polish, let's add a DataPager, just below the DataGrid.  Note that the binding for the DataPager is identical to that for the DataGrid, and that the DataPager retrieves 10 records at a time; we'll go up so that and change the DomainDataSource load size to 30, so that it will retrieve 3 pages-worth at a time.

<data:DataPager PageSize="10" 
  Source="{Binding Data, ElementName=BlogsDataSource}"  />


 

SortedAndFiltered

 

 
 
 
 
 
 
 
 
 
 
 
 
 
Published Friday, September 25, 2009 6:42 PM by jesseliberty

Comments

# RIA Svcs Data Source Control - Jesse Liberty - Silverlight Geek

Thank you for submitting this cool story - Trackback from DotNetShoutout

Friday, September 25, 2009 7:21 PM by DotNetShoutout

# re: RIA Svcs Data Source Control

Ok, Jesse, explain to me why 22 lines of repetitive, deeply indented, angle brackets without much benefit from intellisense, is better than 3 short, clear lines of code.

Zero code-behind? Make me laugh again!

This is the dumbest idea we've hatched in ages.

Friday, September 25, 2009 11:43 PM by WardB

# re: RIA Svcs Data Source Control

Ward,

That wasn't a tweak, it was a shot across the bow :-)

You'll have to point out for me, which 22 lines of repetitive deeply indented code you mean -- are we talking about RIA Services or are we talking about Data Entities?

I will certainly argue that Data Entities needs another round before it's fully ready for prime time, and of course RIA Services hasn't even really been released yet.

That said, if the 22 lines are auto-generated, I'll take that any day for drag-and-drop programming.  If the 22 lines are mine, then I need to take a hard look at re-factoring, and it may not be a problem with the framework at all.

Zero code behind?  Not my goal.  But programming at a higher level of abstraction, and effective encapsulation -- those certainly are high on my radar of attractive features.

Saturday, September 26, 2009 3:41 PM by jesseliberty

# re: RIA Svcs Data Source Control

You are on, my friend!

I refer to the 22 lines of XAML in your post. I was comparing it to the three lines you commented out at the top of the post.

Lest you argue that your XAML sorts the results and provides filtering, I will write 8 lines (one of them a brace) to accomplish the same thing.

 // Place after InitializeComponent

 var bc = new BlogsContext();

 LoadBlogs(bc)

 filterText.TextChange += delegate {LoadBlogs(bc);}

..

private void LoadBlogs(BlogsContext bc){

 bc.Load(bc.GetBlogsQuery().Where(b=> b.BlogName.Contains(filterText.Text).OrderBy(b=>b.BlogName);

 blogsDataGrid.ItemsSource = bc.Blogs;

}

This is terrible code! But it is no worse than the DDS XAML, it is clear, and it does essentially the same things.

You could protest about all of the wonderful things that the DDS can do that I haven't done. Like on-demand page loading.

You would be missing my point. To be clear, I welcome a component to help with pre-loading and paging.

My point is that it takes a ridiculous amount of XAML to accomplish in an obscure way what is most easily done in code ... perhaps better with the aid of a helper component.

I must add that when I write the code, I am openning the way to addressing other issues such as the handling of inevitable errors in retrieval. When I have grown up a little more, I will move this code away from the view's code-behind and into a supporting class. I then have a fighting chance of testing it and devising a coherent data retrieval approach that works properly across the entire application.

Ignoring these concerns and repeatedly implementing one-off data retrieval scenarios in each view is begging for trouble.

But I digress. Here I was lampooning the notion that writing code with XAML is easy.

Do you say "the XAML is easier for non-programmers to read. C# has (gasp) lambda."

Are you sure? Only a subset of visual design people (call them designers) will be able to write your XAML by hand. Those that can (if the HTML crowd is a guide), have mastered "<%=..>". Surely they can handle this.

And shouldn't we be afraid if they cannot?

Of course someone will say "We can make a visual tool to do this!" ... and indeed it will be done ... with great effort ..so that designers someday will gleefully pollute their views with repetitious, fragile, error prone, untestable code.

This is a triumph?

I am not asking you to change your mind about DDS or the wisdom of using it.

I am saying you have a responsibility. Your readers are often new to Silverlight and some are new to programming in .NET.

You honor them and your colleagues - at no cost to yourself - when you say to them: "there are many reasonable developers with long experience who believe the approach I have just shown you is a terrible way to go.  Here is what they say."

Saturday, September 26, 2009 5:40 PM by WardB

# re: RIA Svcs Data Source Control

Thanks Jessy for the tutorial,

I like the features of the dds control.

I may be crazy (my wife says so)

But i like to control stuff in code.

So im a bit torn.

Guess ill try it out,

always room to change.

Saturday, September 26, 2009 7:14 PM by docasio1

# Daily tech links for .net and related technologies - September 26-28, 2009

Daily tech links for .net and related technologies - September 26-28, 2009 Web Development 10 Things

Sunday, September 27, 2009 3:52 AM by Sanjeev Agarwal

# re: RIA Svcs Data Source Control

Wardb,

Let's distinguish between the specifics of using a DomainDataSource control on the one hand, and declarative vs. programmatic (e.g. xaml vs. C#) on the other.

For example, while I'm not suggesting this is in any way a desirable thing do, you *can* use the DomainDataSource programmatically:

[ Remove the declaration from the Xaml file, and add the following to your blogs.xaml.cs:

     private DomainDataSource dsc = new DomainDataSource();

     private BlogsContext bc = new BlogsContext();

     public Blogs()

     {

        InitializeComponent();

        Loaded += Blogs_Loaded;

     }

     void Blogs_Loaded( object sender, RoutedEventArgs e )

     {

        dsc.LoadSize = 30;

        dsc.QueryName = "GetBlogsQuery";

        dsc.AutoLoad = true;

        dsc.DomainContext = bc;

        dsc.SortDescriptors.Add( new System.Windows.Data.SortDescriptor( "BlogName", System.Windows.Data.SortDirection.Ascending ) );

        dsc.FilterDescriptors = new System.Windows.Data.FilterDescriptorCollection();

        dsc.FilterDescriptors.Add( new System.Windows.Data.FilterDescriptor( "BlogName", System.Windows.Data.FilterOperator.Contains, "Silver") );

        this.blogsDataGrid.ItemsSource = dsc.Data;

        dsc.Load();

     }

, again, I'm not arguing you should do this, nor that is efficient, nor that it is maintainable.  I'm only pointing out that we want to distinguish between the use of the control and the choice of declarative programming in Xaml.

Even admitting that this particular control is almost always used declaratively, it is true that there is (or will be) a CLR class for each control. Thus while they are tightly coupled, the control vs. functional code decision is distinct from the programmatic vs. declarative decision.

The advantage of using the declared DomainDataSource as shown in the mini-tutorial  is, at a minimum, that it is "toolable" -- that is that you can easily use such a thing in tools such as Visual Studio and Expression Blend, whereas doing so with C# is much harder.

You can certainly argue that being toolable is a *bad* thing on the grounds of too much "bad" code generated; but I suspect that you will find that many reasonably careful programmers prefer to code in a drag-and-drop way rather than by hand.  One could surely make the argument that the advantages of declarative programming may outweigh what you see as the ugliness of the generated code.  

My personal approach to dealing with generated code is more or less the same as my approach to optimization at any level; which is get things working in the most direct and easiest to understand way; focusing on the highest level of abstraction where possible; and then fix  as needed once you prove that a the real problem exists.

Finally, for me it is early days to know whether using a control like this is going to create maintenance problems.  I suspect, however, that we can agree that this is not the only place that this question arises;  in Silverlight and in other technologies (e.g., WPF, ASP.NET, etc.)

What you have made me aware of, is that we certainly need a white paper and/or a robust discussion on the advantages and disadvantages of declarative code.

I will take my tweaked nose back to the team, and see what others have to say.  Thanks for opening up this important discussion.

-jesse

Sunday, September 27, 2009 2:51 PM by jesseliberty

# re: RIA Svcs Data Source Control

Good points all. Raising awareness about possibilities and tradeoffs is the key ... and you have done that. Thank you.

Many will appreciate the reminder that anything you can do in XAML you can do in code; XAML is essentially a declarative way of constructing and configuring objects. Your sample will help many understand what the 22 lines of markup look like as code.

For the record, I have nothing against tooling; couldn't live without it.

And I like declarative style for hiding implementation details and especially for clearing out the extraneous details that obscure what we are trying to accomplish; it's a style that is as helpful in "normal" programming languages (C#, VB, Ruby, etc.) as it is in XAML (although langs differ markedly in their support for this style).

I'm usually operating on the assumption (false in demos) that I'm going to live with this code for a year or more and that others after me will have to read it and pick up the pieces. My first pass won't be the last pass at the matter being coded.

Accordingly, I am rarely impressed by how quickly I can produce code. I am more concerned about the prospects for supporting/evolving it over time.

My primary rule for generated code is simple: answer "yes, pretty much" to the question, "Would I accept this generated code if I had written it myself?"

In pursuing that thought I ask other questions:

- is it easy to read and understand?

- is it economical (as in, doesn't repeat itself ... here or across the app)?

- is this code in the "right" place?

- can I change / extend it appropriately?

- can I regenerate to accommodate changes harmlessly?

- can I debug it?

- can I test it?

These are questions, not fiat. I don't demand perfection. I'm prepared to hold my nose.

But only to a point and always with the frank admission that a bad smell indicates trouble ahead. Dragging along a growing heap of decay will slow the project ... sooner or later.

Darn. I just meant to say "thanks" ... and here I am, clogging your blog.

From now on, my lips are stapled :-)

Sunday, September 27, 2009 3:33 PM by WardB

# re: RIA Svcs Data Source Control

I seem to have a problem with the XAML DDS not passing data to the DataGrid. The  query is invoked and appears to return the data back through the context ok, but the DataGrid remains blank. I subsequently tried using the blogs.xaml.cs code you blogged Ward which works perfectly. Any ideas as to what I am doing wrong?

 The code for this tutorial is marked as temporarily unavailable - it would be really useful to have to check against.

 Many thanks, as a raw beginner this exercise has been a huge help getting started.

James

Wednesday, September 30, 2009 10:59 AM by jamesclarke

# re: RIA Svcs Data Source Control

Jesse, Ward,  Thanks for the comments and responses this enriched the post about 300% it took it up to a level 300.

I hope you two buy each other a drink at PDC.

Wednesday, September 30, 2009 7:39 PM by sariel

# Programming with Silverlight, WPF &amp; .NET &raquo; The Silverlight Geek Mini-Tutorials

Pingback from  Programming with Silverlight, WPF &amp; .NET &raquo; The Silverlight Geek Mini-Tutorials