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.

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.