Editing in SharePoint’s SPGridView
February 18th, 2010
The goal of this post is to provide an easy to understand example of how to enable editing in an SPGridView. In this case, my datasource of choice is a SharePoint list.
The way that I chose to implement editing in an SPGridView involved two classes:
- SimpleLogic – handles query and update operations
- SimpleSPGrid – handles all of the setup for the ObjectDataSource and the SPGridView
The main advantage for splitting the two classes is to separate all of the business logic into one class. Ideally, you should be able to completely change how the SimpleLogic class retrieves/updates data without changing the SimpleSPGrid code.
The Setup
In this example, our logic class is retrieving and updating data in a SharePoint list. My SharePoint list had three main columns: Title (text), Region (choice), and Total Sales (currency).
Now that I had some data to read from and write to, I was ready to create my logic class.
The SimpleLogic Class
The goal for the logic class was to expose all of the operations the gridview would need in order to read or update data:
- public DataTable Select()
How do I get the data? - public List<BoundField> GetColumns()
How do I display the data? - public void Update(Dictionary<string, string> data)
How do I update the data?
{
const string LIST_NAME = "Example Sales Data";
readonly string[] LIST_COLUMNS = null;
readonly string VIEW_FIELDS = string.Empty;
readonly string[] DATA_KEY_NAMES = null;
private SPWeb _currentWeb;
public SimpleLogic(SPWeb currentWeb)
{
_currentWeb = currentWeb;
DATA_KEY_NAMES = new string[1];
DATA_KEY_NAMES[0] = "ID";
LIST_COLUMNS = new string[4];
LIST_COLUMNS[0] = "ID";
LIST_COLUMNS[1] = "Title";
LIST_COLUMNS[2] = "Region";
LIST_COLUMNS[3] = "Total_x0020_Sales";
VIEW_FIELDS = GetViewFields(LIST_COLUMNS);
}
public string[] GetDataKeyNames()
{
return DATA_KEY_NAMES;
}
public List<BoundField> GetColumns()
{
List<BoundField> fields = new List<BoundField>();
fields.Add(GetBoundField("ID"));
// we don't want the ID field to be editable so we make it readonly
// readonly will mean a textbox to edit it will not be shown
fields[0].ReadOnly = true;
fields.Add(GetBoundField("Title"));
fields.Add(GetBoundField("Region"));
fields.Add(GetBoundField("Total_x0020_Sales"));
return fields;
}
private BoundField GetBoundField(string name)
{
// do not use SPBoundField (will not work with editing)
BoundField bf = new BoundField();
bf.HeaderText = name;
bf.DataField = name;
return bf;
}
public DataTable Select()
{
SPQuery q = new SPQuery();
q.ViewFields = VIEW_FIELDS;
q.Query = "<Where><IsNotNull><FieldRef Name='Title'/></IsNotNull></Where>";
SPList list = _currentWeb.Lists[LIST_NAME];
SPListItemCollection items = list.GetItems(q);
return items.GetDataTable();
}
private string GetViewFields(string[] columns)
{
StringBuilder sb = new StringBuilder();
foreach (string field in columns)
{
sb.AppendFormat("<FieldRef Name='{0}' />", field);
}
return sb.ToString();
}
public void Update(Dictionary<string, string> data)
{
SPList list = _currentWeb.Lists[LIST_NAME];
int id = Int32.Parse(data["ID"]);
SPListItem item = list.GetItemById(id);
item["Title"] = data["Title"];
item["Region"] = data["Region"];
item["Total_x0020_Sales"] = data["Total_x0020_Sales"];
item.Update();
}
}
DISCLAIMER: When actually implementing the class above, you will probably need to add some sort of error handling. In order to provide a simpler example, the error handling has been omitted.
Once our logic class is functioning correctly, we can work on hooking it up to an SPGridView.
The SimpleSPGrid Class
The SimpleSPGrid class contains most of the guts that will probably be different to you. The first thing to notice is that it takes our SimpleLogic class as a parameter. This allows us to instantiate our logic class beforehand with any parameters that are needed, and then pass it into SimpleSPGrid to use.
{
private SimpleLogic _logic;
private ObjectDataSource _gridDS;
private SPGridView _grid;
public SimpleSPGrid(SimpleLogic logic)
{
_logic = logic;
}
protected sealed override void CreateChildControls()
{
const string GRIDID = "grid";
const string DATASOURCEID = "gridDS";
_gridDS = new ObjectDataSource();
_gridDS.ID = DATASOURCEID;
_gridDS.TypeName = typeof(SimpleLogic).AssemblyQualifiedName;
_gridDS.ObjectCreating += new ObjectDataSourceObjectEventHandler(gridDS_ObjectCreating);
_gridDS.SelectMethod = "Select";
// to handle updates from the grid
_gridDS.UpdateMethod = "Update";
_gridDS.Updating += new ObjectDataSourceMethodEventHandler(gridDS_Updating);
this.Controls.Add(_gridDS);
// create our grid
_grid = new SPGridView();
_grid.ID = GRIDID;
_grid.DataSourceID = _gridDS.ID; // link the grid to the ObjectDataSource
_grid.AutoGenerateColumns = false; // must be false
// generally the primary key field(s)
// these will be passed as an input parameter
_grid.DataKeyNames = _logic.GetDataKeyNames();
// add the column that will allow editing
CommandField command = new CommandField();
command.ShowEditButton = true;
_grid.Columns.Add(command);
// add all of the columns in the datatable to the grid
// any column that is not readonly will be passed as an input parameter
foreach (BoundField column in _logic.GetColumns())
{
_grid.Columns.Add(column);
}
this.Controls.Add(_grid);
}
/// <summary>
/// Consolidates all of the InputParameters (values from the grid)
/// into one dictionary of values to send to the update method
/// </summary>
void gridDS_Updating(object sender, ObjectDataSourceMethodEventArgs e)
{
Dictionary<string, string> data = new Dictionary<string, string>();
foreach (DictionaryEntry entry in e.InputParameters)
{
string value = entry.Value == null ? null : entry.Value.ToString();
data.Add(entry.Key.ToString(), value);
}
e.InputParameters.Clear();
e.InputParameters.Add("data", data);
}
/// <summary>
/// When the ObjectDataSource is created, hook it up to the Logic class
/// (so that it uses the Logic class to make the Select, Update... calls)
/// </summary>
private void gridDS_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
e.ObjectInstance = _logic;
}
}
Wrap up
Now that all the hard work is done, we are ready to use the classes inside our web part. Inside the CreateChildControls of your webpart you would have the following code ( even though we have an SPWeb here, it should NOT be disposed):
This will produce the following grid!
And clicking edit…




March 5th, 2010 at 10:46 am
Just Great m8
May 24th, 2010 at 11:58 pm
This is a great solutions and i was able to make use of this. I had an additional requirement of adding a textbox and search a field based on user entry. I was able to filter the data but if the user edits and update, the old data is coming instead of a the newly edited one. One change i have done apart from your code is enabling the filtering and my data source is an SQL server DB. I am stuck for past some days, would appreciate if you can help me.
January 14th, 2011 at 2:50 am
Great Articles
Thanks a lot for that !
Just a proposition :
Can you add a button “new” to create a new line in the list ?
January 15th, 2011 at 3:54 pm
Glad to help!
In my opinion, the easiest way to implement a “new” button is to use separate controls. For example, using the scenario above you’d simply create three textboxes (Title, Region, Total Sales) and the “new” button. You would probably add them right after
this.Controls.Add(_grid)in SimpleSPGrid’sCreateChildControls(_grid)method.March 15th, 2011 at 6:32 pm
Hello,
I noticed the Total Sales field is not formatted to show the currency formatting, i.e. it displays ’10000′ instead of ‘$10,000′.
Do you know how you might display the currency formatting?
Thanks
March 15th, 2011 at 7:38 pm
Nicholas,
You can use the BoundField DataFormatString property. For example, you would change SimpleLogic’s GetColumns function:
sales.DataFormatString = "{0:C}";
fields.Add(sales);
Thanks,
Kit
April 28th, 2011 at 4:24 am
Hi , thanks for this Tuo , If i have a lookup field , theres is any changements to do ? thanks
April 28th, 2011 at 7:17 am
Ahmed,
Yes there will probably be some changes required for lookup fields depending on your requirements (ex: display column in a dropdown?). I think you’ll probably want to take a look at using a TemplateField instead of a BoundField.
Thanks,
Kit
April 29th, 2011 at 5:40 am
Hi Kit Menke,
Thanks a lot for the article.
It worked fine after small change in first part.
April 29th, 2011 at 8:03 am
Hi Kit,
I’ve another column in the List say “Manager” and it’s a People Picker.
Then, how do I update it in the GridView webpart.
Thanks
April 29th, 2011 at 1:09 pm
Thanks Kit , it work with lookup filed also without probléme , can i insert in spgridview and add a new ligne in my grid ? thanks a lot for your time and help
April 29th, 2011 at 5:28 pm
Ahmed,
I think you’re talking about the ability to add new items? If so, the easiest method is to just place the controls underneath the grid (instead of actually making it a part of the grid (similar comment).
Pradeep,
The updates would be pretty similar. However, the real problem is displaying the data in the SPGridView. You’d probably want to use a people picker control:
http://vspug.com/dwise/2008/05/01/inside-the-sharepoint-people-picker/
Thanks,
Kit
P.S. I would encourage you guys to post questions to http://sharepoint.stackexchange.com/. It is a great community for asking SharePoint related questions.
September 14th, 2011 at 11:22 pm
Very very slick.
Thank you very very much
January 20th, 2012 at 5:06 am
hi friend am new to sharepoint
i insert the data in to sharepoint list when i click on the submit how i to display the that inserted data in gridview please help me
January 25th, 2012 at 8:45 am
Vamshi,
You simply could redirect back to the same page and re-query the data from the list? This would refresh your grid. It is hard to tell what you’re doing without code, so I would recommend asking a question on http://sharepoint.stackexchange.com/
Thanks,
Kit