Click here to Skip to main content
Click here to Skip to main content

Edit Individual GridView Cells in ASP.NET

By , 14 Nov 2009
 

Introduction

The ASP.NET GridView allows for a row of data to be edited by setting the EditIndex property of the GridView, placing the entire row in edit mode.

You may not want the entire row in edit mode if you are using DropDownList controls for several columns in the EditItemTemplate. If each DropDownList has many options, then loading them all at once may result in a sluggish page. Also, if your data structure is more like a 2 dimensional array rather than a set of rows, you may want to edit each cell individually.

Here I will demonstrate how to achieve this and also how to deal with Event Validation without disabling it.

Background

This article is based on questions I was asked in relation to one of my previous articles: Clickable and Double Clickable Rows with GridView and DataList Controls in ASP.NET.

To understand the concept of making a GridView row clickable, you may want to read it before proceeding.

Edit Individual GridView Cells

Screenshot - EditGridviewCells1.jpg

The GridView in the demo has an asp:ButtonField control called SingleClick in the first column with its visibility set to false.

This is used to add the click event to the GridView rows.

<Columns>
    <asp:ButtonField Text="SingleClick" CommandName="SingleClick"
                        Visible="False" />
</Columns>

For each of the other columns, there is an item template with a visible Label control and an invisible TextBox, DropdownList or CheckBox control.

For convenience, we will call the Label the "display control" and the TextBox, DropdownList or CheckBox the "edit control".

<asp:TemplateField HeaderText="Task">
    <ItemTemplate>

        <asp:Label ID="DescriptionLabel" runat="server"
            Text='<%# Eval("Description") %>'></asp:Label>

        <asp:TextBox ID="Description" runat="server"
            Text='<%# Eval("Description") %>' Width="175px"
            visible="false"></asp:TextBox>

    </ItemTemplate>
</asp:TemplateField>

The idea here is that initially the data is displayed in the display control and when the cell containing the display control is clicked, it's visibility is set to false and the edit control's visibility is set to true. The EditItemTemplate is not used.

Within the RowDataBound event, each cell of the row is looped through and has a click event added.

The cell index is passed in as the event argument parameter so that the cell can be identified when it raises an event.

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // Get the LinkButton control in the first cell
        LinkButton _singleClickButton = (LinkButton)e.Row.Cells[0].Controls[0];
        // Get the javascript which is assigned to this LinkButton
        string _jsSingle = ClientScript.GetPostBackClientHyperlink(
            _singleClickButton, "");

        // Add events to each editable cell
        for (int columnIndex = _firstEditCellIndex; columnIndex <
            e.Row.Cells.Count; columnIndex++)
        {
            // Add the column index as the event argument parameter
            string js = _jsSingle.Insert(_jsSingle.Length - 2,
                columnIndex.ToString());
            // Add this javascript to the onclick Attribute of the cell
            e.Row.Cells[columnIndex].Attributes["onclick"] = js;
            // Add a cursor style to the cells
            e.Row.Cells[columnIndex].Attributes["style"] +=
                "cursor:pointer;cursor:hand;";
        }
    }
}

Within the RowCommand event, the command argument and the event argument are retrieved. This gives us the row and column index of the selected cell.

int _rowIndex = int.Parse(e.CommandArgument.ToString());
int _columnIndex = int.Parse(Request.Form["__EVENTARGUMENT"]);

Since the row and column indexes of the selected cell are known, the cell can be set to edit mode by setting the visibility of the display control to false and that of the edit control to true.

The attributes of the selected cell are also cleared to remove the click event.

// Get the display control for the selected cell and make it invisible
Control _displayControl =
    _gridView.Rows[_rowIndex].Cells[_columnIndex].Controls[1];
_displayControl.Visible = false;
// Get the edit control for the selected cell and make it visible
Control _editControl =
    _gridView.Rows[_rowIndex].Cells[_columnIndex].Controls[3];
_editControl.Visible = true;
// Clear the attributes from the selected cell to remove the click event
   _gridView.Rows[_rowIndex].Cells[_columnIndex].Attributes.Clear();

There is also some code to set the focus on the edit control after a postback. If the edit control is a DropDownList, then its SelectedValue is set to the value of the display control, if it is a TextBox then its text is selected so that it is ready for editing and if it is a Checkbox then its checked value is set to that of the display control.

// Set focus on the selected edit control
ClientScript.RegisterStartupScript(GetType(), "SetFocus",
    "<script>document.getElementById(
    '" + _editControl.ClientID + "').focus();</script>");
// If the edit control is a dropdownlist set the
// SelectedValue to the value of the display control
if (_editControl is DropDownList && _displayControl is Label)
{
    ((DropDownList)_editControl).SelectedValue = (
        (Label)_displayControl).Text;
}
// If the edit control is a textbox then select the text
if (_editControl is TextBox)
{
   ((TextBox)_editControl).Attributes.Add("onfocus", "this.select()");
}
// If the edit control is a checkbox set the
// Checked value to the value of the display control
if (_editControl is CheckBox && _displayControl is Label)
{
    (CheckBox)_editControl).Checked = bool.Parse(((Label)_displayControl).Text);
}

In the demo, a history of the events fired is also written to the page. Within RowUpdating each cell in the row is checked to see if it is in edit mode. If a cell in edit mode is found, then the data update code is called.

In the first demo page, some sample data is held in a DataTable which is stored in session.

// Loop though the columns to find a cell in edit mode
for (int i = 1; i < _gridView.Columns.Count; i++)
{
    // Get the editing control for the cell
    Control _editControl = _gridView.Rows[e.RowIndex].Cells[i].Controls[3];
    if (_editControl.Visible)
    {
       .... update the data
    }
}

To ensure that RowUpdating is fired after a cell is edited, it is called in Page_Load. By hitting "Enter" after editing a TextBox or clicking another cell, the page is posted back and the checks are made to ensure any data changes are saved.

if (this.GridView1.SelectedIndex > -1)
{
    this.GridView1.UpdateRow(this.GridView1.SelectedIndex, false);
}

Register the Postback or Callback Data for Validation

The custom events created in RowDataBound must be registered with the page.

The ClientScriptManager.RegisterForEventValidation is called by overriding the Render method.

The UniqueID of the row is returned by GridViewRow.UniqueID and the UniqueID of the button can be generated by appending "$ctl00" to the row's UniqueID.

protected override void Render(HtmlTextWriter writer)
{
    foreach (GridViewRow r in GridView1.Rows)
    {
        if (r.RowType == DataControlRowType.DataRow)
        {
            for (int columnIndex = _firstEditCellIndex; columnIndex <
                r.Cells.Count; columnIndex++)
            {
                Page.ClientScript.RegisterForEventValidation(
                    r.UniqueID + "$ctl00", columnIndex.ToString());
            }
        }
    }

    base.Render(writer);
}

This will prevent any "Invalid postback or callback argument" errors from being raised.

Other Examples in the Demo Project

Editing Individual GridView Cells Using a SQL Data Source Control

Implementing this technique with a SqlDataSource control requires some modifications to the GridView's RowUpdating event. A SqlDataSource control normally takes the values from the EditItemTemplate to populate the NewValues collection when updating a GridView row.

As the EditItemTemplate is not being used in this scenario, the NewValues collection must be populated programmatically.

e.NewValues.Add(key, value);

There is a simple SQL Server Express database in the App_Data folder for the data.

(Depending on your configuration, you may need to modify the connection string in the web.config).

Editing Individual GridView Cells Using an Object Data Source Control

This example uses the two classes in the App_Code folder:

  • Task.cs - is the Task object
  • TaskDataAccess.cs - manages the Task object

The code behind of the ASPX page is identical to that in the SQL Data Source example.

The ObjectDataSource manages the data through the GetTasks and UpdateTask methods in the TaskDataAccess.cs class.

GridView with Spreadsheet Styling

This example has a GridView which is styled to look like a spreadsheet.

(Although it looks like a spreadsheet, it does not really behave like a spreadsheet, it's still a GridView after all!)

The principle is the same as above although there is some extra code which changes the cell styles when they are clicked, etc.

Screenshot - EditGridviewCells2.jpg

GridView with Spreadsheet Styling Using a SQL Data Source Control

This example is the same as above but with some modifications to the GridView's RowUpdating event to allow it to work with a SqlDataSource control.

References

Conclusion

If you want to edit data in an ASP.NET GridView one cell at a time, then this technique may be useful.

History

  • v1.0 - 25th Mar 2007
  • v2.0 - 7th Apr 2007
    • Examples using SqlDataSource and ObjectDataSource added to the demo project
  • v3.0 - 23rd Nov 2007
    • Examples with paging and sorting added to the demo project
    • ASP.NET 3.5 web.config added to demo project
  • v4.0 - 5th Nov 2009
    • Examples with UpdatePanel, Validator Controls, and CheckBox added to the demo project
    • VB.NET examples added to demo project

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Declan Bright
Architect
Ireland Ireland
Member
I have been designing and developing business solutions for the aviation and telecommunications industries since 1999. My experience covers a wide range of technologies and I have delivered a variety of web and mobile based solutions.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 4memberWebBHTAN22 Feb '13 - 1:45 
Better article to refer ...
Questionmultiple data sourcesmemberhussyass27 Jul '12 - 12:09 
the example of the spread sheet demonstrates how i can read update and delete data from one table.
what am looking for is to update data in a table selected from a dropdownlist.
for example i have a table called 8 red and a table called 9blue
 
at first the user will select which table he will edit then the gridview will display data from his selected data source and update data within that table
 
any way this can come true??
 
thank you
QuestionDeleting a rowmemberMember 81196449 Apr '12 - 12:58 
Hey your grid is very powerfull and i like it,
but now i got a problem because i want to delete a row,
if i use gridview_rowdeleting event, then this event is also fired if i want to edit a row and if i try to add a buttoncolumn then the singleclick button was overrides by delete button...have you an answer ??
Thanks
Markus
QuestionHandling Tab keymembereliaso54 Jan '12 - 12:04 
How could we handle the TAB key to move to the next cell in Edit mode?
 
Thanks,
Eli
GeneralMy vote of 4memberVarun Sareen28 Dec '11 - 18:19 
Might help me later in my project. A good concept
GeneralGetting an Errormembereliaso517 Dec '11 - 18:01 
I have Vidsual Studio 20'10, I donloaded the project, open as a web site, and when I try to rebuild the web I get the following error:
 
Error 1 It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS. C:\Users\Eli\Desktop\EditGridviewCells_src\EditGridviewCells\Web.Config 22
 
How can be this fixed?
 
Thanks,
Eli
GeneralMy vote of 5memberRaviRanjankr13 Nov '11 - 4:27 
Nice article Thumbs Up | :thumbsup:
GeneralMy vote of 5memberAnurag Gandhi2 Oct '11 - 20:45 
Very Nice Article.
QuestionNice articlememberJohn Felix5 Jul '11 - 19:28 
Million thanx to the author who saved me alot of time.
 
I am a beginner to dotnet and was wondering whether it is possible to code editable details view control. I know that details view control comes with the in-built edit option which will make our lives easy. But I want to challenge....is it possible to write a clickable (also double clickable) with all coding done within the code behind?
 
I tried it myself, but as i am a beginner I couldnt proceed much further.
 
Any help/suggestions...or the solution itself will be valuable information.
 
Thanx folks...
John
GeneralIndex out of rangememberGene Lamm4 Jun '11 - 1:32 
Get index out of range on following stmt:
Dim _displayControl As Control = _gridView.Rows(_rowIndex).Cells(_columnIndex).Controls(1)Index
Using VB.net 2010
GeneralIndex was out of rangememberchitmm20 Mar '11 - 22:04 
Line: 938
Error: Sys.WebForms.PageRequestManagerServerErrorException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
 
How to solve?
GeneralRe: Index was out of rangememberMember 402313031 Oct '11 - 3:35 
hi
GeneralRe: Index was out of rangememberMember 402313031 Oct '11 - 3:36 
test
GeneralFor Select,Insert,Update and Delete in GridView without writting C# or Vb Codemembervijay_vignesh26 Jan '11 - 1:20 
try this link
 
http://vijayvigneshonflex.blogspot.com/p/how-to-do-insertupdatedelete-and-select.html[^]
QuestionHow to set the Label width to fixed value in gridview?memberG.Suman Babu13 Jan '11 - 3:16 
Hi Friend,
 
How to set the Label width to fixed value in gridview?
 
this is very urgent for me plz.. help.
 
Thanks,
Suman Babu.G
QuestionCopy data from multiple cells and paste into another group of cells?membersKyaHbOy28 Dec '10 - 21:28 
Hi,
 
May i know is it possible to select a may be 3 columns in the same row and paste into another 3 cells in a different row?
 
Anyway a very big thanks to the author for the article. Really helpful!
GeneralMy vote of 5memberSTRICQ23 Dec '10 - 12:42 
Simple and clear explanation.
GeneralI need to show the entire been selected however, need only a particular cell on that row to be selectable and updateablememberMember 280198415 Nov '10 - 7:32 
i have been trying to modify your code to achive this but will not work it always updating once a row is been selected
 

#Region "GridView1"
 
Protected Sub gvTicketsummary_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
' Get the LinkButton control in the first cell
Dim _singleClickButton As LinkButton = DirectCast(e.Row.Cells(0).Controls(0), LinkButton)
' Get the javascript which is assigned to this LinkButton
Dim _jsSingle As String = ClientScript.GetPostBackClientHyperlink(_singleClickButton, "")
 
' If the page contains validator controls then call
' Page_ClientValidate before allowing a cell to be edited
If Page.Validators.Count > 0 Then
_jsSingle = _jsSingle.Insert(11, "if(Page_ClientValidate())")
End If
 
' Add events to each editable cell
For columnIndex As Integer = _firstEditCellIndex To e.Row.Cells.Count - 1
' Add the column index as the event argument parameter
Dim js As String = _jsSingle.Insert(_jsSingle.Length - 2, columnIndex.ToString())
' Add this javascript to the onclick Attribute of the cell
e.Row.Cells(columnIndex).Attributes("onclick") = js
' Add a cursor style to the cells
e.Row.Cells(columnIndex).Attributes("style") += "cursor:pointer;cursor:hand;"
Next
End If
End Sub
 
Protected Sub gvTicketsummary_RowCommand(ByVal sender As Object, ByVal e As GridViewCommandEventArgs)
Dim _gridView As GridView = DirectCast(sender, GridView)
 
Select Case e.CommandName
Case ("SingleClick")
' Get the row index
Dim _rowIndex As Integer = Integer.Parse(e.CommandArgument.ToString())
' Parse the event argument (added in RowDataBound) to get the selected column index
Dim _columnIndex As Integer = Integer.Parse(Request.Form("__EVENTARGUMENT"))
' Set the Gridview selected index
_gridView.SelectedIndex = _rowIndex
' Bind the Gridview
_gridView.DataBind()
 
' Write out a history if the event
Me.Message.Text += "Single clicked GridView row at index " & _rowIndex.ToString() & " on column index " & _columnIndex & "<br />"
If _columnIndex = getColumnID("AssignedTo") Then
 

' Get the display control for the selected cell and make it invisible
Dim _displayControl As Control = _gridView.Rows(_rowIndex).Cells(_columnIndex).Controls(1)
_displayControl.Visible = False
' Get the edit control for the selected cell and make it visible
Dim _editControl As Control = _gridView.Rows(_rowIndex).Cells(_columnIndex).Controls(3)
_editControl.Visible = True
' Clear the attributes from the selected cell to remove the click event
_gridView.Rows(_rowIndex).Cells(_columnIndex).Attributes.Clear()
 
' Set focus on the selected edit control
ScriptManager.RegisterStartupScript(Me, [GetType](), "SetFocus", "document.getElementById('" & _editControl.ClientID & "').focus();", True)
' If the edit control is a dropdownlist set the
' SelectedValue to the value of the display control
If TypeOf _editControl Is DropDownList AndAlso TypeOf _displayControl Is Label Then
DirectCast(_editControl, DropDownList).SelectedValue = DirectCast(_displayControl, Label).Text
End If
' If the edit control is a textbox then select the text
If TypeOf _editControl Is TextBox Then
DirectCast(_editControl, TextBox).Attributes.Add("onfocus", "this.select()")
End If
End If
Exit Select
End Select
End Sub
 
''' <summary>
''' A DataSource control normally takes the values
''' from the EditItemTemplate to populate the NewValues
''' collection when updating a GridView row.
''' As the EditItemTemplate is not being used in this scenario
''' the NewValues collection must be populated programatically.
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
Protected Sub gvTicketsummary_RowUpdating(ByVal sender As Object, ByVal e As GridViewUpdateEventArgs)
Dim _gridView As GridView = DirectCast(sender, GridView)
Dim key As String = ""
Dim value As String = ""
 
' Determine the currently logged on user's UserId
Dim currentUser As MembershipUser = Membership.GetUser()
Dim currentUserId As Guid = CType(currentUser.ProviderUserKey, Guid)
 
' The keys for the NewValues collection
'Dim _columnKeys As String() = New String() {"Description", "AssignedTo", "Status"}
 
If e.RowIndex > -1 Then
' Loop though the columns
For i As Integer = _firstEditCellIndex To _gridView.Columns.Count - 1
' Get the controls in the cell
Dim _displayControl As Control = _gridView.Rows(e.RowIndex).Cells(i).Controls(1) ''getColumnID("AssignedTo")
Dim _editControl As Control = _gridView.Rows(e.RowIndex).Cells(i).Controls(3) ''getColumnID("AssignedTo")
 
' Get the column key
'key = _columnKeys(i - _firstEditCellIndex)
key = "AssignedTo"
 
' If a cell in edit mode get the value of the edit control
If _editControl.Visible Then
If TypeOf _editControl Is TextBox Then
value = DirectCast(_editControl, TextBox).Text
ElseIf TypeOf _editControl Is DropDownList Then
value = DirectCast(_editControl, DropDownList).SelectedValue
End If
 
' Add the key/value pair to the NewValues collection
e.NewValues.Add(key, value)
e.NewValues.Add("UserId", currentUserId.ToString)
''Else
' else get the value of the display control
''value = DirectCast(_displayControl, Label).Text.ToString()
 
' Add the key/value pair to the NewValues collection
''e.NewValues.Add(key, value)
End If
 
Next
' Clear the selected index to prevent
' another update on the next postback
_gridView.SelectedIndex = -1
End If
End Sub
 
Function getColumnID(ByVal columnName As String) As Integer
 
For Each column As DataControlField In gvTicketsummary.Columns
 
If column.HeaderText = columnName Then
 
Dim columnID As Integer = gvTicketsummary.Columns.IndexOf(column)
 
Return columnID
 
End If
 
Next
 
End Function
 
#End Region
 
#Region "Render Override"
 
' Register the dynamically created client scripts
Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
' The client events for GridView1 were created in GridView1_RowDataBound
For Each r As GridViewRow In gvTicketsummary.Rows
If r.RowType = DataControlRowType.DataRow Then
For columnIndex As Integer = _firstEditCellIndex To r.Cells.Count - 1
Page.ClientScript.RegisterForEventValidation(r.UniqueID & "$ctl00", columnIndex.ToString()) ''
Next
End If
Next
 
MyBase.Render(writer)
End Sub
 
#End Region
End Class
GeneralMy vote of 5memberuma ashankar26 Oct '10 - 3:22 
jhkjh
GeneralAchiving Editable individual gridview cells for dynamically bind grid.memberb_rajmalla5 Oct '10 - 3:42 
Hi Declan,
 
Its Great article....
 
How can i acheive same for dynamically bind gridview i.e i'm binding gridview in code behined file by writing select query.my girdviews column's are autogenerated & having more than 50 columns (these columns will change based on specific condition select by the user some times more than 50) in which i need to make only few columns editable.thats why i cant mention all the columns in aspx page.
 
thank you in advance...
GeneralMy vote of 1membermathizory5 Aug '10 - 21:53 
does'nt provide the exect code
GeneralMy vote of 4memberMember 404700420 Jul '10 - 23:49 
very usefull article.... Smile | :)
GeneralUse in Web User Control [modified]membercalin7426 Apr '10 - 22:22 
Hi
 
first i have to say, i was a Java web-developer over 15 years. so please don't hurt me because of my dumb question - i work with ASP.NET now for 2 month. so i am converted to ASP.NET Blush | :O
 
i tried to include this into a Web User Control. is this possible? it seems to me, that no events are released (e.g. the 'GridView1_RowCommand'). but your example is running in my IIS.
 
my architecture is the following:
i have an aspx witch is including (with Placeholders) a control (i am loading the control in the code with the LoadControl(...) method).
 
i found the following out:
- with placeholder, it does not work.
- including it direct onto a page (@Register .....) it does work. but i need to work with placeholder to bind dynamic controls to runntime.
 
thank you for helping

modified on Tuesday, April 27, 2010 5:29 AM

GeneralFocus to the control fails. Can you help me? - Can't move focus to the control because it is invisible...memberMember 33470136 Apr '10 - 9:59 
First of all Many thanks for the wonderful article.
 
Upon clicking on the cell I get the following error,
 
"Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus."
 
And the debugger point to following line
document.getElementById('ATMETabContainer_RealTimeTabPanel_RealTimeGridView_ctl02_REActionText').focus();Sys.Application.initialize();
 
Here is my Grid data
 

<asp:TemplateField HeaderText="Action">
 
<ItemTemplate>

<asp:Label id="REActionLabel" runat="server" Text='<%# Eval("Action") %>' CssClass="labeltxt"></asp:Label>

<asp:TextBox id="REActionText" runat="server" Text='<%# Eval("Action") %>' Width="450px" Rows="7" CssClass="ctrltxt" TextMode="MultiLine" Visible="false"></asp:TextBox>

</ItemTemplate>

<ItemStyle VerticalAlign="Top"></ItemStyle>

</asp:TemplateField>
 

 
Did anyone experienced the same error?
 
Thanks in Advanced
GeneralRe: Focus to the control fails. Can you help me? - Can't move focus to the control because it is invisible...memberMember 33470139 Apr '10 - 10:16 
Never Mind!!!
 
Soon after I placed the GridView inside an UpdatePanel, the SetFocus start working perfectly and it improved the overall functionality way much better than I had with out UpdatePanel.
 
Thanks again.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 14 Nov 2009
Article Copyright 2007 by Declan Bright
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid