The SPGridView is one of the most ubiquitous controls used in SharePoint. Every single list in SharePoint (and as we all know there’s lots of those!) uses the SPGridView to display its data in neatly formatted rows. We’re able to sort its data, filter it and click on an item to choose from any options available on that item, amongst other options.

When we build a custom Web Part, we suddenly find ourselves without all that SharePoint goodness. The standard GridView (found in System.Web.UI.WebControls) gives us all the abilities we look for, but it takes a lot of effort to make it look like a SharePoint grid. Luckily, there’s the SPGridView (found in Microsoft.SharePoint.WebControls). It inherits from the GridView so can do whatever the GridView can do. But it does it in style – SharePoint style.

The ASPGridView in action

Getting the SPGridView to look and perform just like the standard SharePoint grids does require some work but with the right choices we can limit this to the absolute minimum. Let’s get started.

To host our SPGridView control we’ll need a basic Web Part skeleton which you can find as part of the files attached to this post. There’s nothing special about it, it serves simply as a place to drop our control. You can of course also use the standard Web Part-User Control pattern.

We’ll use a standard DataTable as the data source for our SPGridView which we’ll bind to an ObjectDataSource (found in System.Web.UI.WebControls). I’ve found the ObjectDataSource easier to use than a DataSet (for example, sorting and paging require no additional code whatsoever) and I haven’t quite had time to dive into using the SPDataSource. Once I have, I’ll be sure to update this post as needed.

Our SelectData method will look as follows:

public DataTable SelectData()
{
    DataTable dataSource = new DataTable();
 
    dataSource.Columns.Add("ID");
    dataSource.Columns.Add("Name");
    dataSource.Columns.Add("Region");
    dataSource.Columns.Add("Total Sales");
 
    dataSource.Rows.Add(1, "J. Smith", "Europe", 10000);
    dataSource.Rows.Add(2, "J. Smith", "North America", 15000);
    dataSource.Rows.Add(3, "J. Smith", "Asia", 5000);
    dataSource.Rows.Add(4, "S. Jones", "Europe", 7000);
    dataSource.Rows.Add(5, "S. Jones", "North America", 30000);
    dataSource.Rows.Add(6, "S. Jones", "Asia", 8700);
    dataSource.Rows.Add(7, "W. Nguyen", "Europe", 3000);
    dataSource.Rows.Add(8, "W. Nguyen", "North America", 50000);
    dataSource.Rows.Add(9, "W. Nguyen", "Asia", 25000);
 
    return dataSource;
}

We’ll be initializing our objects in the CreateChildControls method:

protected sealed override void CreateChildControls()
{
    const string GRIDID = "grid";
    const string DATASOURCEID = "gridDS";
 
    gridDS = new ObjectDataSource();
    gridDS.ID = DATASOURCEID;
    gridDS.SelectMethod = "SelectData";
    gridDS.TypeName = this.GetType().AssemblyQualifiedName;
    gridDS.ObjectCreating += new ObjectDataSourceObjectEventHandler(gridDS_ObjectCreating);
    this.Controls.Add(gridDS);
 
    grid = new SPGridView();
    grid.ID = GRIDID;
    grid.DataSourceID = gridDS.ID;
    grid.AutoGenerateColumns = false;
 
    // Paging
    grid.AllowPaging = true;
    grid.PageSize = 5;
 
    // Sorting
    grid.AllowSorting = true;
 
    this.Controls.Add(grid);
 
    SPGridViewPager pager = new SPGridViewPager();
    pager.GridViewId = grid.ID;
 
    this.Controls.Add(pager);
}

There are a few things to note here. One, I am setting the DataSourceID property of the SPGridView control instead of the DataSource property. This is required to enable filtering later on. I’ve no idea why, but I am grateful to Robert Fridén for figuring this out.

Second, I am setting the TypeName of the ObjectDataSource to the ASPGridView control itself. This allows us to access all the properties of the ASPGridView in our GetDataSource method which will prove useful when we’ll perform data binding against a SPList. It does introduce a problem where the ObjectDataSource “cannot find a non-generic method ‘GetDataSource’ …”. It also introduces a problem with the ObjectDataSource creating a fresh instance of our ASPGridView control, which resets our sorely-needed properties. Fortunately, the fix is surprisingly simple.

When ObjectDataSource creates an instance of the type specified through its TypeName property it raises the ObjectCreating event. In this event, we simply assign our current object instance to the object instance the ObjectDataSource is expecting to use:

private void gridDS_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
    e.ObjectInstance = this;
}

Finally, most blogs will tell you that you need to set the PagerTemplate property of the SPGridView to null. I am using the SPGridViewPager here so we don’t need to. In addition, we get the actual paging behavior used by SharePoint without having to implement any of the Paging events.

If you have read other articles which describe the SPGridView you’ll have noticed that I am not creating the columns for the SPGridView here. I used to until I discovered a strange problem when using more than one ASPGridView on the same page. When I’d set the Visible property of one of the controls to False, the headers of the other control would disappear! To prevent this, I’m generating my columns and performing data binding in the Render method:

protected sealed override void Render(HtmlTextWriter writer)
{
    GenerateColumns();
    grid.DataBind();
    base.Render(writer);
}

And that’s all we need to create a simple SPGridView that supports paging and sorting out-of-the-box.

You can see our progress so far here. Also, you can download the solution I created for this part of the series here. The solution uses the WSPBuilder. To install the demo Web Part, simply build the solution and run the Setup.exe file. Then activate the newly created feature in your SharePoint site and add the Web Part to the page.

I hope this post was useful to you. If so, let me know. If you find that there are things missing, I’d love to hear from you, too.

Erik

References:

If you liked this post, please click on one of the advertisements below. Thanks!


50 Responses to “Building A SPGridView Control – Part 1: Introducing the SPGridView”

  1. 1 Josh

    Nice and clean way of SPGridview Usage! Thanks…

    I tried refactoring an old webpart of mine in this fashion. I have a problem though using a custom templatefield that contains a button.

    I added a rowCommand-event handler in the CreateChildControls method just before the Controls.Add(grid) – call. This worked fine in my old implementation, now little devil won’t fire.

    If you have faced this issue before, I would be most grateful if you could give me a hint…

  2. 2 Erik Burger

    Hi Josh,

    Thanks for the compliment, I am glad you liked the article.

    I haven’t faced the particular issue you describe but I have been using TemplateFields in the SPGridView so I might be able to help you out. I’ll try to create your situation, i.e. add a TemplateField containing a button and see if I can get it to work. If you can send me some (snippets of) code you’re using that’d be great, you can send them to burger.erik at gmail dot com.

    Erik

  3. 3 BhakthiL

    Great article…very informative

  4. 4 Clarence

    YOU ARE DA MAN!!! …especially with the SPGridViewPager!!! Thank you!

  5. 5 Erik Burger

    You are very welcome Clarence. I was quite pleased when I found the SPGridViewPager myself as it matches the standard SP look-and-feel better 🙂 Glad you found the post useful.

    Erik

  6. 6 spmikey

    Using SPGridViewPager as you suggest, the SharePoint page number does not render. In this case,
    PagerTemplate == “System.Web.UI.TemplateBuilder”. Any idea why the SharePoint paging is missing?
    (Setting PagerTemplate=null, displays GridView page numbers below the grid as normal).
    Thanks.

  7. 7 Erik Burger

    Hi,

    The SPGridViewPager does not provide page number but row numbers, which is the OOB behaviour of SharePoint which is why I use it. If you use PagerTemplate == null you will get page numbers.

    Maybe I am missing what you are asking. Please let me know if I do so I can try helping out further.

    Regards,

    Erik

  8. 8 Beekermd03

    Great article! Really helped me out with my SPGridView.

    I want to filter a date column, but I want to filter it by years. Possible? I do not want every date showing up in the filter list. Is there a way to fix this?

    Thanks!!

  9. 9 Erik Burger

    Hi Mike,

    Glad it helped you out! I haven’t been able to edit the filter list in the way you propose but it’s a very interesting idea. I’ll be sure to look into it and if I come up with anything I will let you know 🙂

    Cheers,
    Erik

  10. 10 Juha Kukko

    Hi,

    Thanks for your usefull post! One note:
    I found out that if I had grid.DataBind(); – method called inside the Render method the SelectData is called twice. When I moved grid.DataBind(); -call to OnPreRender method, I got rid of the second SelectData -call.
    If SelectData method takes some time (call to other datasource), it decreases performance to call it twice (in vain). (Only difference from your code is that I call GenerateColumns from CreateChildControls instead of Render)

    Br,
    Juha

  11. 11 Erik Burger

    Hi Juha,

    Thanks for your feedback. If the SelectData method takes more time it is definitely a good idea to structure the code as you did. Well done!

    Erik

  12. 12 Lapin

    Thanks for all, nice post, all works very well 🙂

  13. 13 Erik Burger

    You are very welcome 🙂

  14. 14 carlos

    great article, and very easy to understand.

    I have a situation where the customer wants me to re-create the checkin/checkout functionality on a doc lib and using a gridview.

    this is to be a POC, and I’ve never done anything like it. do you have any suggestions where start. I have not idea how create or re-create the dropdown box as it is used in the document name in a doc lib.

    any suggestions will be creatly appreciated….

  15. 15 carlos

    ps: I’ve been given just tow days to do this and I’m begining to think this is not a two day deal….

  16. 16 Erik Burger

    Hello Carlos,

    I’m afraid I do not quite understand what it is your customer wants you to do. When you say ” the dropdown box as it is used in the document name” do you mean the context menu? If you are looking to build that, Part 3 of my series might be a good place to start. Then you could call the required checkin/checkout commands in response to the menu commands.

    Am I getting close to what it is you are asking? If not, feel free to drop me a line and I will try to help you out more before your deadline. But I think you are correct, two days seems very tight for custom development work.

    Erik

  17. 17 Grzegorz

    Where is metod GenerateColumns() ?

  18. 18 Erik Burger

    If you download the source you should be able to find it.

    Regards,

    Erik

  19. 19 Indrajeet Kumpavat

    Thanks Erik,

    Very good and detailed article..

    Keep Posting!!

    Regards,
    Indrajeet

  20. 20 Erik Burger

    Thank you very much for the compliment Indrajeet, I’ll do my best to get some more posts up soon!

  21. 21 Karthik

    Hi Erik! Great post! Thanks for saving my life by makin gme understand by simplifying the process.

    I’m trying to do that same but in a Application Page with Code Behind. Essentialy writing the following codeblock inside on_pageload. But I don’t understand when gridDS is defined as ObjectDataSource, before initializing it?

    const string GRIDID = “grid”;
    const string DATASOURCEID = “gridDS”;

    gridDS = new ObjectDataSource();
    gridDS.ID = DATASOURCEID;
    gridDS.SelectMethod = “SelectData”;
    gridDS.TypeName = this.GetType().AssemblyQualifiedName;
    gridDS.ObjectCreating += new ObjectDataSourceObjectEventHandler(gridDS_ObjectCreating);
    this.Controls.Add(gridDS);

    grid = new SPGridView();
    grid.ID = GRIDID;
    grid.DataSourceID = gridDS.ID;
    grid.AutoGenerateColumns = false;

    // Paging
    grid.AllowPaging = true;
    grid.PageSize = 5;

    // Sorting
    grid.AllowSorting = true;

    this.Controls.Add(grid);

    SPGridViewPager pager = new SPGridViewPager();
    pager.GridViewId = grid.ID;

    this.Controls.Add(pager);

  22. 22 Erik Burger

    Hi Karthik,

    GridDS is a simple private variable of the class, in your case your page. Does that answer your question?

    Regards,

    Erik

  23. 23 Carlos

    Thanks for your great example. I’ve been researching for how to create a SPGridView for 1 and a half day and I finally found your post!

  24. 24 Erik Burger

    You are very welcome Carlos, glad I could help!

  25. 25 kiko

    I am trying to add grouping to this spgridview but I get the following error it pops up when you databind, any help in trying to figure out this error is appreciated, thanks:

    Object reference not set to an instance of an object.
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

    Source Error:

    Line 56: base.EnsureChildControls();
    Line 57: this.DataSource = SelectData();
    Line 58: this.DataBind();
    Line 59: base.Render(writer);
    Line 60: }

    protected override void CreateChildControls()
    {
    base.CreateChildControls();
    const string DATASOURCEID = “gridDS”;

    gridDS = new ObjectDataSource();
    gridDS.ID = DATASOURCEID;
    gridDS.SelectMethod = “SelectData”;
    this.BorderColor = System.Drawing.Color.AliceBlue;
    this.ID = “ComplianceVisitsGrid”;

    this.AllowGrouping = true;
    this.AllowGroupCollapse = false;

    this.GroupDescriptionField = “ID”;
    this.GroupField = “ID”;
    this.GroupFieldDisplayName = “ID Name”;

    // bind dataset columns to GridView columns
    this.DataKeyNames = new string[] { DataKeysNames.ID };
    BoundField boundField;
    boundField = new BoundField();
    boundField.HeaderText = “ID”;
    boundField.DataField = “ID”;
    this.Columns.Add(boundField);

    boundField = new BoundField();
    boundField.HeaderText = “Name”;
    boundField.DataField = “Name”;
    boundField.HtmlEncode = false;
    this.Columns.Add(boundField);

    boundField = new BoundField();
    boundField.HeaderText = “Region”;
    boundField.DataField = “Region”;
    boundField.HtmlEncode = false;
    this.Columns.Add(boundField);

    boundField = new BoundField();
    boundField.HeaderText = “Total Sales”;
    boundField.DataField = “Total Sales”;
    boundField.HtmlEncode = false;
    this.Columns.Add(boundField);

    }

  26. 26 Max

    thanks! it’s work very fine and now so easy to do. have a g’day!

  27. 27 tokka

    I found a problem with checkbox control. the state of the chekbox is not maintained in the pagination.

  28. 28 Erik Burger

    Hi Tokka,

    Maybe the following link can help out with that: http://aspalliance.com/774

    Regards,

    Erik

  29. 29 subhash

    Hi erik..very nice post ..i found it very usful to use in my project….it suites my requirement but i need to bind the data frm sharepoint list ..can you help me out ..how can accomplish in binding the list data to SPgridview dynamically from sharepoint list with in the same webapplication …thanks in advance..

  30. 30 trofo

    Indeed, you don’t need to use ObjectDataSource. You can query your data in a DataTable and have all the functionality available.

    If you are still interested you can find an example here.

  31. 31 Sumeet Gandhi

    Hi,

    Can you tell me what do i need to do in order to get this working in usercontrol?

    This is what i am doing:

    1. Created a WSP builder proj.
    2. Added a WSP builder projct with webpart as feature.
    3. added a new web app in the same solution.
    4. written a line in web part which will simply call the user control and render on screen.
    5. i want to display data from list into spgridview and this i need to write in user control (ascx file and its cs)

    I hope you got what I am looking for.

    Any guidance will be appreciated.

    Thanks
    Sumeet

  32. 32 Erik Burger

    Hi Sumeet,

    The provided source code contains the solution I use which uses precisely the same organisation as you describe.

    Best regards,

    Erik

  33. 33 Charlie

    Thank you very much for this post. It really helps me a lot to start on my project. I just have a little problem when I applied the grouping, although it grouped, but when i clicked on the next/previous page it throws an error. Even when clicking “Edit page” at site actions. Can you help me please to resolve this issue? Another question: is SPGridView supports Subgroups lets say up to third level?

    What I am trying to implement is to create a webpart that will display a list where it must be group by Company(level 1) then Department as subgroup(level 2), then Section another subgroup(level 3) then from there you will the employees in a section

    Thank you very much and more power!

    Best Regards,
    Charlie

  34. 34 Erik Burger

    Hi Charlie,

    Thank you very much for your kind words. What error are you getting?

    Erik

  35. 35 Prudhvi

    What if SPGridView is created on the fly? For example, a SPGridView inside a Repeater control hosted inside a VisualWebPart. What are changes to be made to make it work.

    In my case, I am getting SPGridView_FilterCallbackErrorHandler() when clicking on the sort column. I could not find any documentation for my scenario where I am creating SPGridView control on the fly.

    Thanks much in advance.

  36. 36 Erik Burger

    If you use a repeater you are creating multiple instances of the SPGridView on the same page. This doesn’t work in the latest version of my code but Paul put up a fix in a comment here.

    Hope this helps.

  37. 37 Prudhvi

    Thanks for the help but the problem prevails. Here is what I am doing..

    protected void rptBlocks_itemBound(object sender, RepeaterItemEventArgs e)
    {
    Panel pnlBlocks = e.Item.FindControl(“pnlBlocks”) as Panel;
    ASPGridView grid = new ASPGridView();
    pnlBlocks.Controls.Add(grid)
    }

    ASPGridView is the exact same control(with exact same test data from your download) and my repeater has 3 items. When I click on the column dropdown, it throws me the same SPGridView_FilterCallbackErrorHandler() error.

    Am I missing anything here? Thanks in advance.

  38. 38 Erik Burger

    I don’t think the problem is in how you add the grids to your page. Did Paul’s tip change anything in the error you are receiving?

    What is the exact error you are getting?

    Erik

  39. 39 Prudhvi

    Thanks so much for your reply. When I am clicking on the column header’s menu to see the sort options, the menu (with all the ‘Sort Ascending’, ‘Sort Descending’) drops down and I get the javasctip error like this –

    ERROR:SPGridView_FilterCallbackErrorHandler() was called – result=There was an error in callback., context=ctl00_SPWebPartManager1_g__ctl00_rptBlocks_ctl00_ctl00_ctl00_grid;ctl00_grid_SPGridViewFilterMenuTemplate;ctl00_grid_ctl01_SPGridViewMenu6;NameH

    It looks like the problem with Sort menu binding with the column header. And Yes, I did update the SPGriedViewProxcy class with Paul’s tip. You can actually replicate this even at your end. Just place a Panel in a Repeater and add the ASPGridView to the Panel on ItemDataBound and you will see this error.

    Thanks much.

  40. 40 Erik Burger

    I’m afraid I am currently swamped in other work so I have no time to reproduce the problem on my end. I am very sorry about that as I’d love to help you out better than I am now.

    One question that popped into my head is whether the identifiers in the error are the same no matter which grid’s menu you click on. Also, are you able to use the debugger to get into the flow of the filter callback? And also (questions keep popping up 🙂 ) if you place multiple grids by hand do you still get the error? It might be easier to debug if you take out the repeater (and put it back in later, of course).

    Erik

  41. 41 gowtham

    can anyone provide me full code for sorting,paging & filtering? thanks in advance;-)

  42. 42 Erik Burger

    The link in the 4th installment of the article contains the latest code at the time of writing. If you merge the various contributions made in the comment you should be able to come up with the complete code.

  43. 43 Sandi

    What id i am using a existing SharePoint List that is already stored on my SharePoint Site…what do I do? I obviously wont be needing the DataTable SelectData()…Please Help…i’ve been working on this for a week and im still new to SharePoint. Thank you.

  44. 44 Sandi

    I still don’t understand what you mean? What comment?

  45. 45 varinder

    When you sort then an arrow image come with the sorted column. I want to change that image with my custom image. Please let me know how can i achieve this

  46. 46 Erik Burger

    Hi Sandi,

    I am so sorry, it seems my comments and emails got lost somehow.

    As far as I can tell you have two options. One is to keep using the SelectData method and simply querying your list for the data you want. The second is to use the SPObjectDataSource which specifies a list as a datasource. It should be a drop-in replacement for the standard DataSource used in the code.

    Hope this helps,

    Erik

  47. 47 Erik Burger

    Hi Varinder,

    My guess is that the image is managed through CSS. So I would suggest looking at the CSS properties/classes used to display the arrow image and overriding those in a custom css file.

    Erik

  1. 1 » SPGridView : Filtering Florent Clairambault
  2. 2 Building A SPGridView Control – Part 1: Introducing the SPGridView « palanivelp
  3. 3 Spdatasource templatefield | Premierpb

Leave a Reply


*