Migrating to the GridView and ObjectDataSource

I "adopted" a small app recently written in .NET 1.1, which I migrated to .NET 2.0 painlessly. It's only about 16 pages and user controls, so I wasn't expecting too many problems with the actual migration into VS 2005, and had none.

Of course, there's a difference between an app that runs against .NET 2.0 and a true .NET 2.0 app. To this end, I converted the main table of data on one of the main pages from a DataGrid to a GridView control. This too was rather painless--mainly replacing "Column" and "Item" in class/property names with "Field" and "Row".

Converting it from doing data binding manually in code to using an ObjectDataSource in markup was a bit more work, though. Deleting automatically was a dream--I specified the delete method we already had, and removed the code that manually implemented delete against the DataGrid from the code-behind, and that was all it took. (This, I might add, has been my overall experience with ASP.NET 2.0--add a new feature like a master page or theme to your web site, delete a bunch of code--which is a lot of fun.) However, for selecting data to display in the table, I ran into some surprises, as well as when implementing sorting, which was one of the new features I was adding to the app during this development cycle.

- A pattern used in this app is lightweight objects used mainly to store data, and separate objects to encapsulate the logic to instantiate these objects from database query results. As far as I could determine from the docs and Google searches, the ObjectDataSource doesn't support this. If you want to bind custom objects, you must do so using a method on the same class that you use to store the data, and specify that class using the TypeName property. To me this seemed a bit short-sighted; why doesn't the ObjectDataSource take two class names, one for the type to be bound, and another for the class with the method(s) to do so, which defaults to the bound type if you don't specify it? I created a short method on my lightweight class that just calls the other method, and it worked fine.

- One thing touted about the GridView over the DataGrid was how easy sorting and paging and so forth go. Sure, the DataGrid supports sorting and paging, one developer evangelist told a large group of us, but you have to write much of the code to do the sorting and paging yourself. With the GridView, you get it free. Well, not in this case. Turn on sorting, click on a column header, and it gives you this (very helpful and descriptive, at least) exception:


[NotSupportedException: The data source 'MyDataSource' does not support sorting with IEnumerable data. Automatic sorting is only supported with DataView, DataTable, and DataSet.]
   System.Web.UI.WebControls.ObjectDataSourceView.CreateEnumerableData(Object dataObject, DataSourceSelectArguments arguments) +425
   System.Web.UI.WebControls.ObjectDataSourceView.ExecuteSelect(DataSourceSelectArguments arguments) +2652
   System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback) +13
   System.Web.UI.WebControls.DataBoundControl.PerformSelect() +140
   System.Web.UI.WebControls.BaseDataBoundControl.DataBind() +68
   System.Web.UI.WebControls.GridView.DataBind() +5
   System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound() +61
   System.Web.UI.WebControls.GridView.OnPreRender(EventArgs e) +24
   System.Web.UI.Control.PreRenderRecursiveInternal() +88
   System.Web.UI.Control.PreRenderRecursiveInternal() +171
   System.Web.UI.Control.PreRenderRecursiveInternal() +171
   System.Web.UI.Control.PreRenderRecursiveInternal() +171
   System.Web.UI.Control.PreRenderRecursiveInternal() +171
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5731



So not only did I have to write a pass-through method to the one I already had to retrieve the data, I now had to change it from a simple pass-through to duplicate the functionality of my original select method, returning a DataTable instead of a custom collection. Once I did that, I did get my sorting without additional work, but it was disappointing that it couldn't sort my custom collection without me writing a manual sort method; I had hoped it would just sort the data after pulling it out of the collection, the same way we'd sort any list of numbers or strings.

This supports my initial impression of the new ObjectDataSource, SqlDataSource, etc. classes, that while it might be great for people who are more comfortable w/ XML/HTML markup than with C# code, it's not something I'm going to use everywhere in my applications instead of binding data with a couple lines of C# code. I'm far from writing them off, though, especially if they're used widely enough that they get filled out a bit more in future versions of .NET.

12 Comments

  • I believe you can create a comparer class for your custom collection to enable sorting support as well for IEnumerable based types returned from your middle tier.



    Alternatively, you can also add an optional "sortexpression" parameter to your objectdatasource type that takes the sortexpression to use as a parameter. This allows you to apply the sort at the middle-tier level, and then just return your strongly typed collection sorted. For example:



    public class ListManager {



    public List<List> GetLists(string sortExpression) {



    }

    }



    Note that the sortExpression passed in would list the column to sort by, as well as whether it is ascending or decending.



    This avoids you having to have a Datatable or DataSet returned.



    Hope this helps,



    Scott

  • Hi,



    I can confirm I have this working for custom collections, and as scott suggested I used the SortExpression, passing it to my middle tier.



    It was only 1 or 2 lines of code I needed to add to enable sorting.



    David Taylor

  • can you post your code here please...i m unable to solve this

  • Can anybody provide a good example of this?

    Thank you
    -Joe

  • "I believe you can create a comparer class for your custom collection to enable sorting support as well for IEnumerable based types returned from your middle tier."

    When you have the comparer class, where do you go from here ? Still need to handle the sorting by hand ?
    TIA

  • omatrot:

    1. Add SortParameterName="SortExpression" to your asp:ObjectDataSource (do this once per sortable control instance)

    2. Create a comparer class (do this once per sortable class)

    3. Create an overloaded select method on your provider object which takes the parameter "string SortExpression" and sorts using the comparer class (instantiated with the SortExpression) (do this once per sortable class)

    All clear?

  • Gil,

    Makes sense, but how do you create a comparer class?

    Thanks,

    Claude.

  • why doesn't the ObjectDataSource take two class names, one for the type to be bound, and another for the class with the method(s) to do so, which defaults to the bound type if you don't specify it?




    The DataObjectTypeName property is meant to specify the type to be bound.

  • Works fine ...
    ... except when EnableCache = True
    Them the NonSupportedError returns!

  • This is just an awful oversight for the objectdatasource to require such hackery to work in a gridview.

  • Has this been resolved with 3.5?

  • What's your view 3 years later on whether

Comments have been disabled for this content.