Linq For Silverlight Developers

 

MiniTutorialLogo

 

ProjectTuringLogo

 Turing Project Page: [Novice: 7]    FAQ    Table of Contents

  What is this and where do I start?

Special Note: This posting introduces a new element in the series: definitions for terms that may not be familiar. Clicking on the link will bring you to the definition page where I will provide a very short explanation of the term and refer you to other postings, videos or books.  In the first sentence under The Blog Class, below, I use the term automatic properties and it is shown as a link. Clicking the link will ring you  to the Definition page, where you will find an entry for automatic properties.

Linq – More Powerful Than A Locomotive

Linq was introduced into .NET with .NET 3.5, and is fully supported in C# 3 and VB9.  It has rapidly become the database language of choice among .NET developers, providing an efficient and “natural” alternative to making calls out to stored procedures or to T-SQL.

You can use Linq for retrieving, updating, removing or adding data to and from SQL-server or any database or from any other collection such as a list<T>, an XML file, etc. An important benefit of this is that the same logic used to retrieve specified data from an in-memory collection may be applied to your data storage layer. That is, rather than using an enumerator on your list but ADO.NET on your database, you can use a Linq query against both.

The following example violates my normal practice of keeping things as simple as possible; I’m doing so consciously to illustrate a fully developed in-memory Linq example that I will walk through in detail. The next posting will demonstrate Linq To SQL, and will give us an opportunity to explore a bit more of Linq.

Let’s start by declaring a class that we can then create a collection of:

   1: using System.Collections.Generic;

   2:  

   3: namespace Linq1

   4: {

   5:   public class Blog

   6:   {

   7:     public string BlogName { get; private set; }

   8:     public string BlogOwner { get; private set; }

   9:     public string BlogUrl { get; private set; }

  10:     public int BlogRanking { get; private set; }

  11:  

  12:     public override string ToString()

  13:     {

  14:       return string.Format(

  15:         "{0} ( {1} ), ranked {2} is owned by {3}",

  16:         BlogName, BlogUrl, BlogRanking, BlogOwner );

  17:     }

  18:   } // end class

  19: }   // end namespace

  20:  

(full source code will be available, so I’m going to indulge in using line numbers)

The Blog Class

The class consists of just four properties (using C#’s automatic properties) and an override of ToString to make it easy to examine what we have. Each instance (blog)  is assigned a ranking so that I can order the blogs in favorite to least favorite.

I will want to generate a collection of these objects, and since I’ll only want to do so for debugging and testing, I’ll incorporate a method to generate that data as a static member of the class (the following code is inserted after the override of ToString and before the brace closing the class:

   1: public static List<Blog> GenerateBlogs()

   2: {

   3:   var blogs = new List<Blog>

   4:               {

   5:                 new Blog

   6:                 {

   7:                   BlogName = "Silverlight Geek",

   8:                   BlogOwner = "Jesse Liberty",

   9:                   BlogUrl = "http://www.SilverlightGeek.me",

  10:                   BlogRanking = 5

  11:                 },

  12:                 new Blog

  13:                 {

  14:                   BlogName = "Mike Harsh's Blog",

  15:                   BlogOwner = "Mike Harsh",

  16:                   BlogUrl = "http://blogs.msdn.com/mharsh/",

  17:                   BlogRanking = 4

  18:                 },

  19:                 new Blog

  20:                 {

  21:                   BlogName = "Brad Abrams",

  22:                   BlogOwner = "Brad Abrams",

  23:                   BlogUrl = "http://blogs.msdn.com/brada",

  24:                   BlogRanking = 3

  25:                 },

  26:                 new Blog

  27:                 {

  28:                   BlogName = "Computer Zen",

  29:                   BlogOwner = "Scott Hanselman",

  30:                   BlogUrl = "http://blogs.msdn.com/hanselman.com/",

  31:                   BlogRanking = 2

  32:                 },

  33:                 new Blog

  34:                 {

  35:                   BlogName = "Scott Gu's Blog",

  36:                   BlogOwner = "Scott Guthrie",

  37:                   BlogUrl = "http://weblogs.asp.net/scottgu",

  38:                   BlogRanking = 1

  39:                 }

  40:               }; // end initialization of collection

  41:   return blogs;

  42: } // end static method

On line 3 we declare blogs using the new var keyword (implicit type) and assign to blogs a new List<Blog>, which we proceed to initialize using object initialization  The net effect is that we end with a list of five blogs, fully initialized, which we can return to any method that needs such a list.

Let’s look at the UI now, which will serve as a spec for building the (simple) application, allowing us to take a look at how Linq can make querying for a subset of the blogs easier (this is a posting about Linq!)

— live demo —

– end live demo –

The rankings used are entirely arbitrary and used only as examples; your mileage may vary, packed by weight not volume.

Notice that you can use the spinner to choose to list between 1 and 5 blogs and as you’ll see they are listed in “rank” order.

The Xaml Behind the Display

The data is of course hard wired, but let’s look at how the data gets from the Blogs class into the data grid.

Step 1 is to create the data grid, the prompt and the spinner.

The trick to using a datagrid is to drag it from the toolbox onto the markup so that Visual Studio will include the right libraries and create the right namespace for you. You can of course, add the reference yourself,

ReferencesForLinq

and then add a namespace/alias at the top of your file

xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

In any case, with that in place, you are ready to add the DataGrid which you can do in the mark up or programmatically. I’ll do so in the markup, telling the DataGrid not to generate the columns, but rather to use the columns I’ll describe:

   1: <data:DataGrid AutoGenerateColumns="False"

   2:                x:Name="BlogGrid"

   3:                Grid.Column="0"

   4:                Grid.Row="1"

   5:                Grid.ColumnSpan="3"

   6:                RowBackground="AntiqueWhite"

   7:                AlternatingRowBackground="LightGreen"

   8:                >

   9:     <data:DataGrid.Columns>

  10:         <data:DataGridTextColumn Header="Blog"

  11:                                  Width="SizeToCells"

  12:                                  Binding="{Binding BlogName}"

  13:                                  FontFamily="Georgia"

  14:                                  FontSize="18" />

  15:         <data:DataGridTextColumn Header="Owner"

  16:                                  Width="SizeToCells"

  17:                                  Binding="{Binding BlogOwner}"

  18:                                  FontFamily="Georgia"

  19:                                  FontSize="18" />

  20:         <data:DataGridTextColumn Header="URL"

  21:                                  Width="Auto"

  22:                                  Binding="{Binding BlogUrl}"

  23:                                  FontFamily="Georgia"

  24:                                  FontSize="18" /> 

  25:     </data:DataGrid.Columns>

  26: </data:DataGrid>

Note that each column is bound to a property in the Blog object; we’ll get the collection of Blog objects in the code behind. Before we do, though, let’s be sure to add the prompt and spinner for the top row:

   1: <TextBlock Text="How many?"

   2:            Grid.Column="0"

   3:            Grid.Row="0"

   4:            FontSize="14"

   5:            FontFamily="Georgia"

   6:            VerticalAlignment="Bottom"

   7:            HorizontalAlignment="Right"

   8:            Margin="5"/>

   9: <inputToolkit:NumericUpDown x:Name="num"

  10:      VerticalAlignment="Bottom"

  11:      HorizontalAlignment="Left"

  12:      Margin="5"

  13:      Width="50"

  14:      DecimalPlaces="0"

  15:      Minimum="1"

  16:      Value="1"

  17:      Grid.Row="0"

  18:      Grid.Column="1" />

Notice that the NumericUpDown comes from the Toolkit. You can read all about the Silverlight Toolkit here, and we have videos on Toolkit controls here.  The NumericUpDown control is handsomely demonstrated in the Toolkit Samples

We make fairly simple use of it, setting its minimum value and its current value to 1.

Implementing The Event Handlers

Turning to the code behind we begin by creating a private member, blogs of type List<Blog>.

In the constructor, we assign to that member variable the result of calling the static method we created in the Blog class. Being extremely careful to make sure that we have data to work with, we then check to ensure that the member variable blogs is no longer null. (lines 8-11)

   1: public partial class MainPage

   2:  {

   3:    private readonly List< Blog > blogs;

   4:    public MainPage()

   5:    {

   6:      InitializeComponent();

   7:      blogs = Blog.GenerateBlogs();

   8:      if ( blogs == null)

   9:      {

  10:        throw new ArgumentNullException( "GenerateBlogs returned null!" );

  11:      }

  12:      num.Maximum = blogs.Count;

  13:      num.ValueChanged += ( (sender, e) => NumValueChanged(sender, e) );

  14:      SetGrid();

  15:    }

  On line 12 we examine how many entries there are in the List<Blog> and set the Maximum value for the NumericUpDown to that number.

We set an event handler for when the user clicks on the NumericUpDown. The syntax may strike you as a bit odd; this is a Lamda Expression (an integral part of Linq as it turns out) and says that we are registering an event whose delegate will match a method that takes two objects and given those two objects will return the result of invoking NumValueChanged and passing in those objects.

Finally, we call the private method SetGrid, which would normally be the contents of the method NumValueChanged, but is factored out so that we can also call it from the constructor.

   1: void NumValueChanged( object sender, System.Windows.RoutedPropertyChangedEventArgs<double> e )

   2: {

   3:   SetGrid();

   4: }

The incredibly astute reader will have noticed that we’ve not assigned an ItemsSource for the DataGrid. That is done on purpose as we’re going to create the ItemsSource out of a selected subset of the member collection blogs.  All of that work happens in SetGrid:

Linq (At Last!)

The job of SetGrid is to retrieve the value from the NumericUpDown and to retrieve that many Blog entries from the collection blogs, based on the BlogRanking that we previously assigned to each entry.

   1: private void SetGrid() 

   2: {

   3:   var result =

   4:     from eachBlog in blogs

   5:     where eachBlog.BlogRanking <= num.Value

   6:     select eachBlog;

   7:  

   8:   BlogGrid.ItemsSource = result;

   9: }

It accomplishes this task by using a Linq query against blogs, the result of which is placed in the anonymous type variable result.  The actual type of that variable, however, is determined by what the Linq statement returns, and that is an object of type IEnumerable<Blog>. 

A quick check of the documentation will show that the ItemsSource property for the DataGrid is looking for an IEnumerable,

ItemsSource

And the last line of SetGrid assigns the variable result to the ItemsSource property, causing the DataGrid to be populated.

Parsing The Linq Query

The Linq query will be quite familiar to anyone who has worked with SQL; the most noticeable difference is that the select statement comes at the end rather than the beginning.

We begin with from eachBlog in blogs  — blogs of course is our collection obtained in the constructor, and eachBlog is a temporary variable of type Blog that is created implicitly just by using it in this way (there is no earlier statement such as

Blog eachBlog;   // not needed

The where statement filters for all the entries where the BlogRanking property of the Blog is less than or equal to the Value currently stored in the NumericUpDown. Thus, if the user sets the NumericUpDown to 3, we’ll get the entries whose ranking (that is, whose property BlogRanking) is 1,2 and 3, as set in the initialization of the Blog entries in the static method.

The select statement adds each of these entries to the IEnumerable result and then, finally result is set as the ItemsSource for the DataGrid. 

The select clause is known by database cognoscenti as the projection.  

In order to get into more advanced aspects of Linq it will be helpful to have a more complex data source; the next posting will take a look at Linq to Sql.

Novice Previous: Database Design Next: Linq To Sql
Advanced Previous: Database Design Next: Linq To Sql
Share

About Jesse Liberty

Jesse Liberty is a Master Consultant for Falafel Software, and has three decades of experience writing and delivering software projects. He is the author of 2 dozen books and multiple Pluralsight courses, and has been a Technical Evangelist for Telerik and for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS.
This entry was posted in z Silverlight Archives and tagged . Bookmark the permalink.

2 Responses to Linq For Silverlight Developers

  1. Having a hard time trying to construct some complex join queries in Silverlight 4. Thanks. Good article.

  2. Rama charan says:

    Thanks for the cool tutorial.

    The screenshot of the application you are developing is not visible.Please fix the same.

    “This webpage is not available.

    The webpage at http://silverlight.services.live.com/invoke/20712/Linq%20Demo%201/iframe.html might be temporarily down or it may have moved permanently to a new web address.”

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>