Practical ASP.NET

Databinding Without Tables: Inserting with the GridView

The final installment in Peter's series on how to use the GridView without a DataSource explores how developers can perform inserts.

This week's column continues a series I began three columns ago, looking at how to build a page that displays multiple data items extracted from a single text property. In this article, I'll provide a way to handle inserting new data from a GridView. I've broken this column into two parts: Data issues and UI issues.

Data Issues
The GridView doesn't support inserts directly, so the mechanism I use is to add a blank row to the underlying data source and then put the resulting row into edit mode. The first step is to add a button to add the new row. For the example that I've been using in this series where I'm working with a table called Parameter in a DataSet called Parameters, I'd put this code in the button's Click event:

Dim ds As Parameters = LoadData()
ds.Parameter.AddParameterRow("", "")
With Me.GridView1            
.DataSource = ds
.EditIndex = Me.GridView1.Rows.Count
            .DataBind()
            SaveData(ds, False)
End With
This code first retrieves the DataSet from the LoadData method I described in the first column (Databinding the GridView without using a Table). The code then uses the Parameter table's customized Add method to insert a new row, passing two zero-length strings to initialize the two fields in the row.

The code then sets the GridView's EditIndex to the number of rows in the GridView in order to display the new row in its EditItemTemplate (trust me -- this works). After adding a blank row to the DataSet, I call my SaveData method to have the XML in the DataSet retained (my SaveData method is also described in last week's article, Databinding without Tables: Updates and Deletes. This time I pass False in the second parameter to the SaveData method, so that the method won't update the business object with a DataSet containing a blank row.

From this point, the code already behind the Update button (described in last week's column, Databinding without Tables: Updates and Deletes) will take care of storing the data.

User Interface Issues
This isn't a perfect solution. If the user clicks the "Add Row" button twice in a row or cancels out of the update, you'll get a blank row added to the DataSet. Preventing the user from clicking the insert button twice is easy: In the button's Click event set either of the button's Enabled or Visible properties to False. Then, in both the RowUpdating and RowCancelingEdit events, set the property back to True.

To handle the user canceling out of the update and leaving a blank row you need to delete the row that you added in the button's Click event. Unfortunately, because I've chosen to save the underlying XML, rather than the whole DataSet (an issue I discussed in the first article in this series), I can't check the row's status to see if it's a new row. I could just check to see if all of the fields in the row are empty and delete any rows that have no data. However that solution could mean that I will delete rows that the user wanted to keep but wanted to be blank.

I've chosen to implement a cheesy solution (and I’m open to better suggestions): I store the position of the row being inserted in the ViewState in the insert button's Click event:

Public Partial Class WebForm
    Inherits System.Web.UI.Page

Protected Sub InsertButton_Click(…
        Me.ViewState("InsertRowPos") = Me.GridView1.Rows.Count
I also initialize this value in my LoadData method when I don't find the XML version of my DataSet in the Session object:

Function LoadData() As DataView
        Dim strXML As String = Me.ViewState("XML")
        If strXML = "" Then
            Me.ViewState("InsertRowPos") = -1
In the RowCanceling event, I check to see if I'm working with that row and delete it if I am. Regardless, I set InsertRow back to its initial value:

ds = LoadData()
If e.RowIndex = Me.ViewState("InsertRowPos") Then
                ds.Parameter.Rows(e.RowIndex).Delete()
                ds.AcceptChanges()
	    SaveData(ds, False)
End If
Me.ViewState("InsertRowPos") = -1
And with that code, I’ve got a full implementation of all the update activities for a grid. With the code in the two earlier articles you can also display and sort data you find in memory, so this also completes the project I started two columns back. All the functionality you need in a GridView but without a table.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

Subscribe on YouTube