Sorting with Silverlight 2's DataGrid Control

So I am just starting to get my feet wet with Silverlight 2.  I have gained some confidence over the past few days, but on the crawl, walk, run scale it feels like I am still crawling.  Beginner or not, I figured I would take a shot at getting Silverlight's DataGrid control to support sorting.  Nothing too complicated - just the standard click on the column header to sort the data.  Surprisingly, I didn't see much on MSDN talking about how to implement sorting using the DataGrid.  I know the documentation is still in the works so I am sure it is coming, but I was a little bit concerned about how to get started.  No worries though, it turned out to be a breeze.  If you are interested in the details, I have a quick description of what I did just beneath the following screen shot.

Live Demo | Download

image

Creating Some Data

If you follow my blog, you may have noticed that I am partial to the Northwind data set.  This example is no different - my grid is filled with the rows from the customers table.  And I cheated a bit and hard-coded my data so I could focus on the sorting interface and not worry about fetching them from the database.  I figure I can work on the web service part later.

I added a Customer class to my application that contains a handful of the attributes defined by the customer table.  Then I added a static Get method to the Customer class that loads the Customer list if it hasn't been loaded already and returns it.  It looks something like this ...

image

And just as a side note, I didn't actually key in all 91 Add statements.  I used a bit of SQL to generate these based on the rows in the customer table.  If you give a lot of presentations, demos or just need to create some test data - don't forget about SQL Server.  It can be very handy as a crude code generation tool when you need something quick. 

image

Defining the DataGrid's Columns

Like ASP.NET 2.0's GridView, the Silverlight DataGrid can infer what column's need to be displayed based on the properties that are found on the data source.  The AutoGenerateColumns property is what controls this behavior.  When it is set to true, the DataGrid automatically adds the columns when the ItemSource property is set.  To be honest though, when working with the GridView I usually don't set the AutoGenerateColumns property to true.  I always want to control the order of the columns, the name (Company Name instead of CompanyName) and often times I do not want to show all of the properties my data source makes available.        

To get this type of behavior, you can use the DataGrid's Columns collection to define the order, header text and type for each of the columns you want displayed.  Like the GridView, you can create different type of column elements based on the data type you are binding to the column to.  Right now it looks like the DataGrid has a DataGridTextBoxColumn for text content, a DataGridCheckBoxColumn for tri-state (Yes/No/Unknown) content and of course a very flexible DataGridTemplateColumn that supports templating. 

Below is a sample where I am explicitly defining the contents of the Columns property using the markup.

image

Adding HyperlinkButton's for the Column Header

If you notice in the above screen shot, I have specified each column's header text using the DataGridTextBoxColumn.Header attribute.  Well it turns out the XAML programming model is pretty darn flexible.  And I could have used the property element syntax to specify the header title by setting the Header property to a TextBlock like so ...

image

And if I replace the TextBlock control with a HyperlinkButton (which exposes a Click event) things start coming together for my sorting scenario.  Now the XAML for the Customer's ID DataGridTextBoxColumn takes on the following form.  Notice I have attached an event handler to the Click event and assigned the Tag attribute to the property I want to sort by.

image

And because I am using the Tag attribute to let me know what property to sort by I can attach all of the column header Click events to the same event handler.  Giving use something like this.

image

Implementing the Click Event Handler

And now for the easy part.  Our Sort_Click event handler will determine what property to sort the Customers collection by from looking at the value of the Tag attribute.  So I have setup a switch statement that orders the in-memory Customers list by the property that corresponds to the column header that was clicked.  One thing to note is that because the DataGrid control doesn't maintain the sort state, I have to keep track of the last sort property and direction to determine how to order the collection (ASC or DESC) if the same header is clicked twice.   

image

That's it.  Enjoy!


TrackBack

TrackBack URL for this entry:
http://mattberseth.com/blog-mt/mt-tb.fcgi/112

Listed below are links to weblogs that reference Sorting with Silverlight 2's DataGrid Control:

» GridViews con estilo from NetC├│digo e Internet
He pensado publicar algunos de los post que tengo en mi otro blog y que han resultado interesantes a [Read More]

» Collegamenti del 28 Marzo, ASP.NET, ASP.NET AJAX, ASP.NET MVC, Visual Studio, Silverlight, .NET from Test
Collegamenti del 28 Marzo, ASP.NET, ASP.NET AJAX, ASP.NET MVC, Visual Studio, Silverlight, .NET [Read More]

» New Visual Design For My Blog from ux musings
As a user experience designer, the visual design of content I produce is an important consideration. [Read More]

Comments


Posted by: Roger Pence on March 26, 2008 12:00 AM

Matt--

Your posts are amazing! I want to be you when I grow up. Keep up the great content.

Sincerely
rp

Posted by: The Chang on March 27, 2008 12:00 AM

Hey your blog rocks... :)

Posted by: Lance on March 27, 2008 12:00 AM

Great post as always, Matt. A helpful technique you or others might consider for sorting grids is the use of Dynamic LINQ. Being able to embed strings in the OrderBy clause will save the use of switch/case blocks to determine the sort ID and code a separate LINQ statement for each one.

Scott Guthrie has a good demonstration here for anyone interested.

Thanks again for the great work.

Hey Matt,

Your article and sample are really awesome.. thanks a lot.. your blog is amazing btw.. full of great articles.

Posted by: Ethan Nagel on March 28, 2008 12:00 AM

Great work, Matt! Ive beeen looking for an example like this for days, and yours certainly does the job! Ive been looking for an elegant way to indicate a sort by including sort direction arrows. This is pretty easy to do in WPF using templates and styles, but I havent found a good way yet in SL2 with its rather odd limitations. Any thoughts on how you could expand this to work with sort direction indicators? For extra credit, is there a way to do it using templates, so you dont have to define the the XAML repeatedly?

Posted by: OAk?n on April 5, 2008 12:00 AM

Its great. But, I want to learn is there any way to take Costumer.Get() under App_Code folder. Probably your Costumer class under SilverlightApplication. I am trying to reach Costumer class from App_Code(Under SilverlightApplication_web) folder. is there any for this? Thanks...

Posted by: Sam Covington on April 6, 2008 12:00 AM

GREAT Sample,

I modified your sort routine to accomidate any object, as shown below.

private void Sort_Click(object sender, RoutedEventArgs e)
{
HyperlinkButton button = sender as HyperlinkButton;

// what property are we sorting by
string sortProperty = button.Tag.ToString();
// what direction are we going
bool isSortAsc = this._lastSortProperty == sortProperty ? !_isLastSortAsc : true;

IEnumerable customers = doSortProperty(sortProperty, isSortAsc);

this.dg.ItemsSource = customers;
this._isLastSortAsc = isSortAsc;
this._lastSortProperty = sortProperty;
}

private IEnumerable doSortProperty(string sortProperty, bool isSortAsc)
{
IEnumerable customers = Customer.Get();
PropertyInfo[] pia = typeof(Customer).GetProperties();
foreach (PropertyInfo pi in pia)
{
if (pi.Name.ToLower() == sortProperty.ToLower())
{
customers = isSortAsc
? customers.OrderBy(c => pi.GetValue(c,null))
: customers.OrderByDescending(c => pi.GetValue(c,null));
break;
}
}
return customers;
}

Posted by: Rui Marinho on April 8, 2008 12:00 AM

Hi there, is very cool this sort for the datagrid.. but it dosent work with numbers... if i have a column of number it dosent order well.

Rui

Posted by: Gary on April 12, 2008 12:00 AM

Per The Changs comment above, with Dynamic LINQ you can do the sorting with:

string sortOrder = isSortAsc ? " asc" : " desc";
IQueryable customerList = Customer.Get().AsQueryable();
var query = customerList.OrderBy(sortProperty + sortOrder);
this.dg.ItemsSource = query;

-Gary

Im having a hard time to select a row by c# code. I have the SelectedItem so wheres the SelectedIndex which I can select by index or get the selected index ???

SilverLight 2.0

Posted by: Alistair Rigney on April 21, 2008 12:00 AM

I would like how to know how to set the selected item as well.
Regards,
Alistair

Posted by: Pete on May 12, 2008 12:00 AM

Hi this is such an amazing article, thank you! I was also wondering has anyone ever managed to get drag and drop column re-ordering within silverlight yet? or is this absolutely not possible

Posted by: Ben Anderson on June 24, 2008 12:00 AM

You rock, wait to go on keeping on top of things. This will be a huge help.

Posted by: IhorCo on June 26, 2008 12:00 AM

Silverlight DataGrid has own sort functionality. How can we disable it?

Hey,
Nice work, I have a question here, Last night i was playing with the datagrid and i could find 2 most important feature, which should be there anyway,

1. There is no rowdatabound event, the closest thing i found was RowLoading event, which fires only once, I was able to change the data using the PropertyChanged event, but I was not able to change the row style.

2. I was unable to access the Cells property of the DataGridRow class, later i found it but marked as internal, why is that?

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Consulting Services

Yep - I also offer consulting services. And heck, I'll do just about anything. If you enjoy my blog just drop me an email describing the work you need done.

Recent Comments

  • Syed Murtaza Hussain Rizvi wrote: Hey, Nice work, I have a question here, Last night i was playing with the datagrid and i could find ...
  • IhorCo wrote: Silverlight DataGrid has own sort functionality. How can we disable it? ...
  • Ben Anderson wrote: You rock, wait to go on keeping on top of things. This will be a huge help. ...
  • Pete wrote: Hi this is such an amazing article, thank you! I was also wondering has anyone ever managed to get d...
  • Alistair Rigney wrote: I would like how to know how to set the selected item as well. Regards, Alistair ...
  • Gary wrote: Per The Changs comment above, with Dynamic LINQ you can do the sorting with: string sortOrder = isS...
  • Marc Roussel wrote: Im having a hard time to select a row by c# code. I have the SelectedItem so wheres the SelectedInd...
  • Rui Marinho wrote: Hi there, is very cool this sort for the datagrid.. but it dosent work with numbers... if i have a c...