Saturday, 24 January 2009

Setting the Initial Sort Order – Dynamic Data

This is just a quick note on a post I made on the Dynamic Data Forum to answer a question where setting the DisplayColumnAttribute should set the default sort order of the GridView on the List page but didn’t. Here’s how I solved it with a hint or two from Marcin Dobosz.

[MetadataType(typeof(Orders_Metadata ))]
[DisplayColumn("OrderID", "OrderID", true)]
public partial class Orders
{
    public class Orders_Metadata
    {
... }
}

Listing 1 – Example Metadata

Assuming you have a table with the DisplayColumnAttribute set you could put this on your List page: 

var displayColumn = table.GetAttribute<DisplayColumnAttribute>();
if (displayColumn != null && displayColumn.SortColumn != null)
{
    GridView1.Sort(displayColumn.SortColumn,
        displayColumn.SortDescending ? SortDirection.Descending : SortDirection.Ascending);
}

Listing 2 – Edit the Page_Load event handler and add the following code

public static T GetAttribute<T>(this MetaTable table) where T : Attribute
{
    return table.Attributes.OfType<T>().FirstOrDefault();
}

Listing 3 – you will also need this extension method see Writing Attributes and Extension Methods for Dynamic Data

Add your DisplayColumnAttribute (see Listing 1) to the table you want sorted (note: it must have the second string constant even if it’s the same name, as the second string it the one that the sort is done on, and the third value if true causes the sort to be descending). Then in Listing 2 you get the attribute using the extension method from Listing 3 and apply the relevant sort.

This is here mainly so I can find it again! HappyWizard

28 comments:

Anonymous said...

Using this method, deletes don't work anymore...

Stephen J. Naughton said...

I'll give that a test and get back to you on this, I think only tested this with DD.

Steve :D

Stuart Whiteford said...

Yep, deletes don't work for me too. Also noticed that I can only navigate up to page 2 with the GridViewPager.

Stuart Whiteford said...

Steve,

Instead of sorting on the GridView, I set the OrderBy property of the underlying LinqDataSource in The Page_Load method and that seems to resolve the deleting and paging issues.

[code]
string orderBy = string.Format("{0} {1}", displayColumn.SortColumn, displayColumn.SortDescending ? "descending" : "ascending");
GridDataSource.OrderBy = orderBy;
[/code]

Anonymous said...

not much help for a newbie...

Stephen J. Naughton said...

Hi Stuart, thanks for that, I'll do an update and cite you for that snippet, do you have a blog or website I can point to in the citation?

Steve :D

Gareth Thomas Hill said...

Thanks again for this - solved my problem!

Unknown said...

Worked perfectly! Thanks.

Stephen J. Naughton said...

Thanks fabriciofuji :)

Steve

Anonymous said...

The code works! But it's better top use it only when the page is not a post back. I was able to delete and re-order.

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var displayColumn = table.Attributes.OfType().FirstOrDefault();
if (displayColumn != null && displayColumn.SortColumn != null)
{
GridView1.Sort(displayColumn.SortColumn,
displayColumn.SortDescending ? SortDirection.Descending : SortDirection.Ascending);
}
}
}

Stephen J. Naughton said...

Good point fabiocanada :)

Steve

Unknown said...

Hi Steve,

Nice tip, but I have a problem. I need to do sort using 2 fields. I try to put other "DisplayColumn". Do you know, how I can do that ?

Thanks

Stephen J. Naughton said...

Hi Yuri, you can just apply multiple column name to the GridView sort, also if you are using VS2010 and .Net 4 then you can add a sort to QueryExtender that should give you the control.

Steve

Unknown said...

Hi Steve,

QueryExtender works fine to me.

Thank you

Stephen J. Naughton said...

Glad it does Yuri :)

Steve

Jonathan Moreau said...

To expand on Stuart Whiteford's code example, the order by syntax when working with an EntityDataSource is slightly different:

string orderBy = String.Format("it.{0} {1}", displayColumn.SortColumn, displayColumn.SortDescending ? "desc" : "asc");
GridDataSource.OrderBy = orderBy;

Also, excluding this sorting code from post backs (as fabiocanada pointed out) allows for re-sorting by the user, but after a delete, for example, the default sort order is lost. The user can then re-sort using the column headers but it's not a good user experience , especially when there are several pages of data.

Stephen J. Naughton said...

Hi Jonathan, I don;t do it that way anymore with .Net 4. I do it liek this, much more relyable.

// set default sort
if (table.SortColumn != null)
{
var order = new OrderByExpression()
{
DataField = table.SortColumn.Name,
Direction = table.SortDescending ? SortDirection.Descending : SortDirection.Ascending,
};
queryExtender.Expressions.Add(order);
}

Jimbo said...

Hi Steve,

I don't know how I found this post but it was a great help, and also got me to learn about extension methods.

Thanks again and I'm bookmarking your site.

Thanks,

Jim

Stephen J. Naughton said...

Glad you like it Jim

Steve

James Manning said...

@Steve - where do you add that code in the .Net 4 version? The Page_Load in List.aspx.cs?

Thanks!

Stephen J. Naughton said...

Hi James see http://csharpbits.notaclue.net/2011/01/setting-initial-sort-order-dynamic-data.html this should be it for .Net 4

Daniel said...

Thank you for your post! It was very helpful!

Stephen J. Naughton said...

Hi Daniel, if you look at the previous post to yours there is a link to th latest version :) for .Net 4 and 4.5

and you are of course very welcome

Steve

Unknown said...

In Page_Load couldn't you simply do:

if (!IsPostBack)
{
if (table.SortColumn != null)
{
GridView1.Sort(table.SortColumn.DisplayName,
table.SortDescending ? SortDirection.Descending : SortDirection.Ascending);
}
}
}

Again thanks for the article it was insightful to start digging more underneath the hood of DD.

Unknown said...

Is it a wise approach to do something like this in the Page_Load of list.aspx.cs:

if (!IsPostBack)
{
if (table.SortColumn != null)
{
GridView1.Sort(table.SortColumn.DisplayName,
table.SortDescending ? SortDirection.Descending : SortDirection.Ascending);
}
}
}

Thank you for the insightful article really got me into DD.

Stephen J. Naughton said...

Hi Johnathan, I actually useht emethod below now as I did have issues with the GidViews sort :)

public static void SetInitialSortOrder(this QueryExtender queryExtender, MetaTable table)
{
// set default sort
if (table.SortColumn != null)
{
var order = new OrderByExpression()
{
DataField = table.SortColumn.Name,
Direction = table.SortDescending ? SortDirection.Descending : SortDirection.Ascending,
};
queryExtender.Expressions.Add(order);
}
}

Steve

trytoreachhigh said...

Hi Steve,
Great to see your posts. I have been using your cascade filter example. Right now I would like to sort the foreign key filter values that are displayed in every page (list/edit/insert/details) without breaking the cascade effect. I have set the initial sort order of the table using the DisplayColumn attribute.
Also, is there a way in which I can choose the order in which the tables in the model get displayed in the main page?

Stephen J. Naughton said...

Hi there, there is a post on my blog called setting initial sort order that will do it.

Also Cascade should follow the DisplayColumn sort attribute sort column.

Steve