I have used this technique before... use the item template for the edit controls and scrape the values by looping through the rows using events other than  edit command.

But I got lost for a bit, this article helped me get back on track: http://www.dotnetjohn.com/articles.aspx?articleid=83

I'm using a gridview control and calling my "ReverseBind" from both page changes and also when the user clicks on a button that takes the final results and transfers the data to other places in the database.

I loop through rows which are actually of type "DataControlFieldCell", the controls I'm interested in are contained in the cells. If you know the control names you can use the FindControl method.

For Each oC In oCell.Controls
Dim ID As String = (oC.ID & String.Empty).ToUpper
If ID.Length > 5 Then
Select Case ID.Substring(0, 5)
Case "ELBL_"
oItem.SetValue(ID.Substring(5), CType(oC, Label).Text)
Case "ECHK_"
oItem.SetValue(ID.Substring(5), CType(oC, CheckBox).Checked)
Case "ETXT_"
oItem.SetValue(ID.Substring(5), CType(oC, TextBox).Text)
Case Else
' don't care
End Select
End If ' Id.length > 5
Next ' control in cell

In this case I have named the controls "ELBL_fieldname", "ETXT_fieldname", "ECHK_fieldname" so I can loop through the controls and determine both type and database field name. I could separate and rename the db and ui field names but why introduce that level of confusion?? To me it is much clearer to maintain the names from end to end so you know what you are looking at.

While I could use some more generic tag and use gettype to determine the type this is much easier for the limited scope of this particular usage.

Passing the the field name and control "value" (.text, .checked) to a simple object (Item) that basically represents the row but also has logic for validation and saving to the DB.