Wednesday, January 04, 2006
« ViewState and the Coalescing Operator (?... | Main | ASP.NET, Tilde (~), Virtual Paths and th... »

NOTE: I have slightly modified this post and the associated source. Make sure to take a look at v2 after reading this post:
http://blog.binaryocean.com/PermaLink,guid,a1ff6cab-dc2d-441c-8557-7dce920d4075.aspx

-Andrew

>>>

In ASP.NET version 1.x, I used the footer on the DataGrid control to insert new rows by placing a series of TextBox, DropDownLists, CheckBoxes etc. controls on it and then handling a save button. This also works with the GridView in version 2.0 but with one major exception: if your data source is empty, the GridView will hide your footer (and header) and only display the EmptyDataText.

Conventional wisdom says that you should use a DetailsView to insert rows, but I don't want to shift the user between two different controls. You can edit and delete rows with a GridView so why not Insert?

Here is the solution. I am using an ObjectDataSource control to wire up my data access class. If the DataTable coming back from my data class is empty, I add a null row. This works fine but now you get blank rows in the GridView. To handle that, I hide the rows during the RowCreated event. Lastly, I clear the controls off of the now hidden row so that there are no binding errors as would be the case with a cast boolean value which I do to set the value of a CheckBox in my GridView.

You can download the entire solution and sample database here:
http://download.binaryocean.com/GridViewInsertSolution.zip

private bool LoadDataEmpty

{

    //  some controls that are used within a GridView,

    //  such as the calendar control, can cuase post backs.

    //  we need to preserve LoadDataEmpty across post backs.

    get { return (bool)(ViewState["LoadDataEmpty"] ?? false); }

    set { ViewState["LoadDataEmpty"] = value; }

}

protected void ObjectDataSourceMain_Selected(object sender, ObjectDataSourceStatusEventArgs e)
{
    //  bubble exceptions before we touch e.ReturnValue
   
if (e.Exception != null)
   
{
       
throw e.Exception;
    
}

    // get the DataTable from the ODS select mothod
    DataTable dataTable = (DataTable)e.ReturnValue;

    // if rows=0 then add a dummy (null) row and set the LoadDataEmpty flag.

    if (dataTable.Rows.Count == 0)

    {

        dataTable.Rows.Add(dataTable.NewRow());

        LoadDataEmpty = true;

    }

    else

    {

        LoadDataEmpty = false;

    }

}

 

protected void GridViewMain_RowCreated(object sender, GridViewRowEventArgs e)

{

    // when binding a row, look for a zero row condition based on the flag.

    // if we have zero data rows (but a dummy row), hide the grid view row

    // and clear the controls off of that row so they don't cause binding errors

    if (LoadDataEmpty && e.Row.RowType == DataControlRowType.DataRow)

    {

        e.Row.Visible = false;

        e.Row.Controls.Clear();

    }

}

 

protected void GridViewMain_RowCommand(object sender, GridViewCommandEventArgs e)

{

    // handle the save button on the footer row. this is the only manual data operation

    // that must be done. update and delete are handled by the gridview and ODS

    if (e.CommandName == "Save")

    {

        string code = ((TextBox)GridViewMain.FooterRow.FindControl("TextBoxCode")).Text;

        string description = ((TextBox)GridViewMain.FooterRow.FindControl("TextBoxDescription")).Text;

        bool isActive = ((CheckBox)GridViewMain.FooterRow.FindControl("CheckBoxIsActive")).Checked;

 

        new LocationData().Insert(code, description, isActive);

 

        GridViewMain.DataBind();

    }

}

 

 

kick it on DotNetKicks.com   Wednesday, January 04, 2006 11:02:54 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [16]  | 
Friday, February 10, 2006 10:12:10 AM (Pacific Standard Time, UTC-08:00)
This is the best solution to the problem of an empty dataset on a grid I have found yet. Thanks!
JBK
Friday, March 24, 2006 4:52:58 PM (Pacific Standard Time, UTC-08:00)
Hey, nice work, this is the best solution I've seen on the web yet! I'm really hoping you have a chance to answer an idiot question...

My particular solution uses an SqlDataSource instead of an ObjectDataSource, and the SqlDataSourceStatusEventArgs class doesn't have a ReturnValue property. How do I retrieve the DataTable so I can add the empty row?

Anyway, thanks for the great info.
Saturday, April 22, 2006 4:53:38 AM (Pacific Standard Time, UTC-08:00)
Very good solution. But unfortunatelly it does not work when I use ObjectDataSource & custom paging (i.e. ObjectDataSource.EnablePaging = true). I spent hours and still have not found a solution :-(. Real headache. Microsoft should have add a property - smth sort of HideGridWhenEmpty. It'd be very useful.
Saturday, August 12, 2006 10:35:09 AM (Pacific Standard Time, UTC-08:00)
But this approach doesn't works when underlying table for gridview has NotNull Fields!
String
dataTable.Rows.Add(dataTable.NewRow());
causes error of such kind: column "FacultyName" doesn't allow null

May be I'm doing something wrong?
Andrey Khataev
Thursday, September 07, 2006 3:07:28 PM (Pacific Standard Time, UTC-08:00)
Great solution, but i have the same trouble...
I have a NotNull field and the solution above return me an error.
Column 'ColumnName' does not allow nulls.

Any suggestion please?.
era
Friday, January 26, 2007 2:49:06 PM (Pacific Standard Time, UTC-08:00)
As others have said, this is the best solution I've found yet. Thanks a ton!

Regarding the NotNull field issue... I had the same trouble. Basically, before you add the new DataRow to the DataTable, you need to set the required values (e.g. DataRow.[RequiredValue] = [Value] where [Value] has the appropriate type. It basically doesn't matter what values you set, because you'll be hiding the dummy/null row, and clearing the controls. So when a user inserts a new row, the dummy row is disregarded altogether.
Michelle L. McCotter
Tuesday, February 06, 2007 7:15:55 AM (Pacific Standard Time, UTC-08:00)
Great Solution!!Bravo.
Hamza
Tuesday, June 05, 2007 1:41:38 AM (Pacific Standard Time, UTC-08:00)
Great solution.
Thanks a lot.
David Potter
Tuesday, July 03, 2007 4:33:50 AM (Pacific Standard Time, UTC-08:00)
Thank you very much for this great solution.
It is better than the EmptyDataTemplate approach (http://geekswithblogs.net/casualjim/archive/2006/05/04/77151.aspx).
Congratulaions.
niazi darwish
Tuesday, December 04, 2007 4:05:19 AM (Pacific Standard Time, UTC-08:00)
alex
Friday, December 07, 2007 6:44:10 AM (Pacific Standard Time, UTC-08:00)
The binary ocean project was really a starting point for me and my activity.
Friday, January 04, 2008 1:22:38 AM (Pacific Standard Time, UTC-08:00)
how to use the above for other datasource not object source.


ravi
Monday, March 17, 2008 4:01:04 AM (Pacific Standard Time, UTC-08:00)
nice code, but --HEY, LOVE THAT LIVE COMMENT PREVIEW!! --as i was saying, other controls, such as detailsview, manage to insert new rows without any manual coding.

would it not be possible to somehow bind your controls to fields, so that it's only necessary to call the insert method on the datasource?

just wondering!
Tuesday, April 15, 2008 3:09:16 AM (Pacific Standard Time, UTC-08:00)
string strSql = "select ClinicID,Name from Clinic";
DataTable dtClinic = new DataTable();
dtClinic.Load(dbManager.ExecuteQuery(strSql));

DataRow dtRow = dtClinic.NewRow();
dtRow["ClinicID"] = 0;
dtRow["Name"] = "--Select--";
dtClinic.Rows.InsertAt(dtRow, 0);

combo_ClinicName.DataSource = dtClinic;
combo_ClinicName.DisplayMember = "Name";
combo_ClinicName.ValueMember = "ClinicID";
Subimal Nath
Thursday, September 11, 2008 12:46:25 AM (Pacific Standard Time, UTC-08:00)
Hey Great Job. Congratulatiosn it's a nice solution. I´m gonna implement it on a project I´m working on.

Regards.
Jorge Abarca
Monday, September 15, 2008 11:34:36 AM (Pacific Standard Time, UTC-08:00)
Great work!!

It's working greate for me.

' Retrieve the selected data from the objectdatasource
Dim dv As DataView = ChkReqLinesDataSource.Select
' assign the datview table
Dim dt As DataTable = dv.Table

' if the number of rows is less than the pagesize of the gridview
If dt.Rows.Count < gvChkReqLines.PageSize Then
Dim intCount As Integer = gvChkReqLines.PageSize - dt.Rows.Count
Dim i As Integer

For i = 1 To intCount
Dim newRow As DataRow = dt.NewRow
newRow("request_id") = i
dt.Rows.Add(newRow)
Next
End If
Hilda
Name
E-mail
Home page

Comment (Some html is allowed: a@href@title, strike) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview