Update SharePoint List Data in a GridView (Part 2)
This is Part 2 of Update SharePoint List Data in a GridView. In the previous post, we added an ‘Edit’ column to the GridView that allowed a user to make modifications to a single row. However, the form controls were automatically generated based on the type of column. What if you wanted to customize the type of control used in each column? This is when GridView templates come into play.
Sample Data
Let’s modify the GridView we used in the last example. This is what it looks like currently.
When you switch to Edit mode, the GridView provides you with default form controls: all of them text boxes except for the check box for the Seasonal column.
We’re going to modify the GridView so that we can use any type of form control that we want in each column.
(1) Customize the GridView Columns
1. Locate the GridView control in the .ascx file of the visual web part we created in Part 1.
1 2 3 4 5 6 7 |
<asp:GridView ID="StarbucksGridView" runat="server" AutoGenerateEditButton="True" AutoGenerateColumns="True" OnRowEditing="Edit_Row" OnRowCancelingEdit="Cancel_Edit" OnRowUpdating="Update_Row" CellPadding="4" EnableModelValidation="True" ForeColor="#333333" GridLines="None"> <!-- Styles omitted --> </asp:GridView> |
2. Set AutoGenerateColumns and AutoGenerateEditButton to False. (Line 2)
1 2 3 4 5 6 7 |
<asp:GridView ID="StarbucksGridView" runat="server" AutoGenerateEditButton="False" AutoGenerateColumns="False" OnRowEditing="Edit_Row" OnRowCancelingEdit="Cancel_Edit" OnRowUpdating="Update_Row" CellPadding="4" EnableModelValidation="True" ForeColor="#333333" GridLines="None"> <!-- Styles omitted --> </asp:GridView> |
3. Switch to Design or Split view, and click on the GridView control in the visual editor. Click the arrow for the Task menu. Then click Edit Columns.
4. In the Fields window, first un-check the box that says “Auto-generate fields”. Then add a BoundField for every field that is going to receive data from a Column in the SharePoint List.
Notice that you can define the properties of that field on the right-hand side, including the HeaderText that will display at the top of the column in the GridView. You can set various useful properties such Visible and HtmlEncode that will apply to the entire column.
Don’t forget to set the DataField property for each field, which maps that BoundField to the Column in the DataTable whenever you bind the GridView.
Next, add a CommandField. You can re-order the fields and place the Edit column wherever you want; here I moved it to the end. Find the Behavior section in the field properties and set ShowEditButton and ShowCancelButton to True.
5. You’ll notice when you click OK that a snippet of code that looks like this will appear inside the GridView. So of course you can type the code if you prefer, instead of using the Fields window.
1 2 3 4 5 6 7 8 |
<Columns> <asp:BoundField DataField="ID" HeaderText="ID" /> <asp:BoundField DataField="Title" HeaderText="Title" /> <asp:BoundField DataField="Size" HeaderText="Size" /> <asp:BoundField DataField="Calories" HeaderText="Calories" /> <asp:BoundField DataField="Seasonal" HeaderText="Seasonal" /> <asp:CommandField ShowEditButton="True" /> </Columns> |
(2) Define Template Fields
Similarly, you can use the Fields window to create the Template fields, or you can type the code.
1. In the Fields window, select each column that you would like to customize and click the “Convert this field into a Template field” blue link.
2. Once you click OK, the <Columns> section will look more like this. Each Field has been converted into a TemplateField, which means you can customize each column, namely the controls used for each column.
Note that each TemplateField has an ItemTemplate and an EditItemTemplate. The ItemTemplate is used when the row is in view (display) mode, and the EditItemTemplate is used when the row is in edit mode.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<Columns> <asp:TemplateField HeaderText="ID"> <EditItemTemplate> <asp:TextBox ID="IDTextBox" runat="server" Text='<%# Bind("ID") %>'></asp:TextBox> </EditItemTemplate> <ItemTemplate> <asp:Label ID="IDLabel" runat="server" Text='<%# Bind("ID") %>'></asp:Label> </ItemTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="Title"> <EditItemTemplate> <asp:TextBox ID="TitleTextBox" runat="server" Text='<%# Bind("Title") %>'></asp:TextBox> </EditItemTemplate> <ItemTemplate> <asp:Label ID="TitleLabel" runat="server" Text='<%# Bind("Title") %>'></asp:Label> </ItemTemplate> </asp:TemplateField> <!-- The rest of the fields here --> <asp:CommandField ShowEditButton="True" /> </Columns> |
3. For the ID field, you can prevent the user from changing the ID value by either disabling the TextBox in the EditItemTemplate, or for a safer solution – changing it to a Label control.
1 2 3 4 5 |
<asp:TemplateField HeaderText="ID"> <EditItemTemplate> <asp:TextBox ID="IDTextBox" runat="server" Text='<%# Bind("ID") %>' Enabled="false"></asp:Label> </EditItemTemplate> </asp:TemplateField> |
1 2 3 4 5 |
<asp:TemplateField HeaderText="ID"> <EditItemTemplate> <asp:Label ID="IDTextBox" runat="server" Text='<%# Bind("ID") %>'></asp:Label> </EditItemTemplate> </asp:TemplateField> |
Note that I omit the ItemTemplate in the examples, but don’t remove it from the actual code.
4. Replace the TextBox with a DropDownList control to the Title field. We will only allow the user to select from a list of values, managed by a completely separate SharePoint list.
You might notice that while the other controls have the attribute Text='<%# Bind("ID") %>'
, this control does not. We will have to set the value programmatically when we populate the dropdown.
1 2 3 4 5 6 |
<asp:TemplateField HeaderText="Size"> <EditItemTemplate> <asp:DropDownList ID="SizeDropDownList" runat="server"> </asp:DropDownList> </EditItemTemplate> </asp:TemplateField> |
5. Next I’m going to use a RadioButtonList for the Seasonal field. Since there are only two possible values, we’ll go ahead and write in the List Items.
1 2 3 4 5 6 7 8 |
<asp:TemplateField HeaderText="Seasonal"> <EditItemTemplate> <asp:RadioButtonList ID="SeasonalRadioButtonList" runat="server"> <asp:ListItem Text="Yes" Value="true" /> <asp:ListItem Text="No" Value="false" /> </asp:RadioButtonList> </EditItemTemplate> </asp:TemplateField> |
6. Finally, in the GridView tag, add another function for the RowDataBound event.
1 2 3 4 5 6 |
<asp:GridView ID="StarbucksGridView" runat="server" AutoGenerateColumns="False" AutoGenerateEditButton="False" OnRowEditing="Edit_Row" OnRowCancelingEdit="Cancel_Edit" OnRowUpdating="Update_Row" OnRowDataBound="Row_Databound"> <!-- ... --> </asp:GridView> |
7. Take care of any other formatting for the GridView, then switch to Code View (F7).
(3) Populate Values for Form Controls
When we click the ‘Edit’ command/link, we have to insert the values into the DropDownList for the user to select.
1. Create a function for the RowDataBound event. Add this to the Row event handlers you made in Part 1.
1 2 3 4 |
protected void Row_Databound(object sender, GridViewRowEventArgs e) { //Put the code for Steps 2-7 here. } |
2. First, check for the Row Type and Row State. Since this event fires for every row that is created, check to see if the Row is a DataRow (not a Header or Footer). Then check if the row is the one in Edit mode.
1 2 3 4 5 |
if(e.Row.RowType == DataControlRowType.DataRow) { if(e.Row.RowState == DataControlRowState.Edit) { } } |
3. Find the DropDownList control by name. Use the FindControl function to select the DropDownList control.
1 2 |
//Find the dropdown control DropDownList ddl = (DropDownList)e.Row.FindControl("SizeDropDownList"); |
4. Get the choices for the DropDownList from a SharePoint List. First, I’m going to create a new Custom list, called DrinkSize, and add a few items. These will be the choices the user can select from the GridView.
Back in my visual web part, I’m going to query that list and create a DataTable out of its items. We’ve already learned how to query a list – this time, instead of using an SPListItemCollection, we use the GetDataTable() function that converts the items into a DataTable.
1 2 3 4 5 6 |
//Get the choices for the DropDownList. SPWeb thisWeb = SPContext.Current.Web; SPList choiceList = thisWeb.Lists["DrinkSize"]; SPQuery queryC = new SPQuery(); DataTable choices = new DataTable(); choices = choiceList.GetItems(queryC).GetDataTable(); |
Instead of a SharePoint list, you can get these choices from any kind of data source, such as a string array, csv file, type them up manually…etc.
5. Get the ‘current’ value and default the dropdown to that value. It is optional, but good practice, to set the Selected Value of the Dropdown to whatever the value for that field is currently. To do that, we must retrieve what that current value is from the table stored as the Session object.
1 2 3 |
//Retrieve the data from the session object. DataTable ds = (DataTable)Session["StarbucksData"]; string selectedSize = ds.Rows[e.Row.RowIndex]["Size"].ToString(); |
6. Finally, bind the data to the DropDownList.
1 2 3 4 5 6 |
//Bind the data to the DropDownList ddl.DataSource = choices; ddl.DataTextField = "Title"; ddl.DataValueField = "Title"; ddl.SelectedValue = selectedSize; ddl.DataBind(); |
7. Set the default value for the RadioButtonList as well. Once again, this is optional, but your users will thank you for it.
1 2 3 4 5 |
//Next the Seasonal Control RadioButtonList rbl = (RadioButtonList)e.Row.FindControl("SeasonalRadioButtonList"); //Retrieve the data from the session object. string selectedSeasonal = ds.Rows[e.Row.RowIndex]["Seasonal"].ToString(); rbl.Items.FindByText(selectedSeasonal).Selected = true; |
(4) Update the RowUpdating Event
Since we defined our columns earlier, and possibly re-ordered them, we should update the RowUpdating event that we wrote in Part 1. If you remember, it currently looks like this:
1 2 3 4 5 6 7 8 9 |
protected void Update_Row(object sender, GridViewUpdateEventArgs e) { //Get the updated values from the controls. //Please note that Cells[0] is the Update/Cancel command column. GridViewRow row = StarbucksGridView.Rows[e.RowIndex]; string id = ((TextBox)row.Cells[1].Controls[0]).Text; string title = ((TextBox)row.Cells[2].Controls[0]).Text; //…the rest of the code goes here… } |
The problem is that the Cell indexes may no longer be correct. It’s better to refer to the controls by name like so:
1 2 3 4 5 6 7 8 9 10 11 12 |
protected void Update_Row(object sender, GridViewUpdateEventArgs e) { //Get the updated values from the controls. GridViewRow row = StarbucksGridView.Rows[e.RowIndex]; DropDownList titleC = (DropDownList)row.FindControl("TitleDDL"); string id = ((Label)row.FindControl("IDTextBox")).Text; string title = ((TextBox)row.FindControl("TitleTextBox")).Text; string size = ((DropDownList)row.FindControl("SizeDropDownList")).SelectedValue; string calories = ((TextBox)row.FindControl("CaloriesTextBox")).Text; string seasonal = ((RadioButtonList)row.FindControl("SeasonalRadioButtonList")).SelectedValue; } |
Then you can store the values in the Session table and SharePoint list. See the previous post for the explanation on how to do that.
Final Steps
- Package and deploy the project.
- Navigate to the site collection or site in SharePoint, depending on the feature scope. Activate the feature with the visual web part.
- Create a new web part page or edit an existing one. When you click insert a web part, the visual web part is under the Custom category.
- Add the visual web part to the page and save.
More Information
Most of this code was gleaned & modified from Microsoft’s documentation on the GridView RowEditing event.
Also see their documentation on all GridView events.
And finally, see their documentation on the page life cycle and Data Binding events.