Click here to Skip to main content
15,878,814 members
Articles / Web Development / ASP.NET
Article

GridView with insert line

Rate me:
Please Sign up or sign in to vote.
4.40/5 (30 votes)
1 Jun 2007CPOL5 min read 436.6K   4.9K   87   102
A GridView with insert line.

Sample Image - grid.gif

Introduction

There are millions of articles written about how to add an insert line to the GridView control. Anything that I got to work more or less suggests to add a FooterRow with appropriate templates. Even that approach breaks apart if the data source is empty - then the GridView just displays an empty line. Both of those problems are addressed in the proposed solution - a HeaderRow is always shown and a FooterRow is automatically populated with appropriate templates/input elements. Also, what sets this solution apart is that no special or additional setup is needed neither for the columns (the use of special types) nor for the footer row or for the data-source/SQL statement - you can use Visual Studio to configure this just like for the DetailsView control.

Using the code

For anyone used to the GridView, the usage is trivial - just drop and configure. The same design-time editor is used, so the GUI is identical. The only thing to make sure is that the data-source Insert command is configured and the the EditFlag (on the GridView) is turned on. Alternatively, you can use VS to configure the GridView and then just change tags to the InsertableGrid.

The following additional events/properties were added to the InsertableGrid (available through the Designer):

  • bool AllowInsert - Defaults to true. Once this property is cleared, it behaves just like the regular GridView.
  • GridViewUpdatedEventHandler RowInserting - The event is fired right before the row insertion. Fill up the default values here, if needed. Same as RowUpdating (got a little lazy here and didn't implement a new delegate - rather reused the one from the update).
  • GridViewUpdatedEventHandler RowInserted - The event is fired just after the insert happens. Check and clear ExceptionHandled (as needed) here, just like you would with RowUpdating.

Additionally, the RowCreated event will be generated for FooterRow, allowing you to fill up some of the input fields with default values:

C#
protected void InsertableGrid1_RowInserted(object sender, GridViewUpdatedEventArgs e) {
    if (e.Exception != null) {
        Label3.Text = e.Exception.Message;
        e.ExceptionHandled = true;
    }
}

protected  void InsertableGrid1_RowCreated(object  sender, GridViewRowEventArgs e) {
    if (e.Row.RowType == DataControlRowType.Footer 
                      && e.Row.DataItem is DataRowView) { 
        DataRowView r = e.Row.DataItem as DataRowView; 
        r["schStart"] = DateTime.Now.ToShortDateString(); 
        r["schEnd"] = DateTime.Now.AddDays(2).ToShortDateString(); 
    } 
}

Points of interest / Implementation details

In order to implement this functionality, the following tasks need to be accomplished:

  • Make sure that the empty GridView still displays a header row.
  • Optionally, create a new FooterRow and fill it up with the same input elements specified for the Edit mode (EditTemplate).
  • Create and process a new Insert command. Generate the appropriate event handlers.
  • Provide for two-way binding for the footer (insert) row so the data on the insert row can be easily initialized.

Make sure header/footer rows are still created

This proved to be quite a task. GridView insists on creating a single cell table when there is no data. To address this issue, I had to override the protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding) method and check the return code from the base class. If the return code is 0 (among all other), then it means that there is no data in the GridView and I need to go and create a header/footer (insert) row. base.CreateRow is used here to create the rows.

C#
int ret = base.CreateChildControls(dataSource, dataBinding);
if (Columns.Count == 0 || DesignMode || !AllowInsert)
    return ret;
DataControlField[] flds = new DataControlField[Columns.Count];
Columns.CopyTo(flds, 0);
if (ret == 0) {
    Controls.Clear();
    Table t = new Table();
    Controls.Add(t);

    GridViewRow r = CreateRow(-1, -1, DataControlRowType.Header,
          DataControlRowState.Normal);
    this.InitializeRow(r, flds);
    t.Rows.Add(r);

    gvFooterRow = CreateRow(-1, -1, DataControlRowType.Footer,
          DataControlRowState.Insert);
    this.InitializeRow(gvFooterRow, flds);
    t.Rows.Add(gvFooterRow);
}
else
    gvFooterRow = base.FooterRow;

Fill-up footer/insert row with edit elements

I thought it would be quite a chore to have to define all the same templates for the footer row as for the edit rows. That was what most of the solutions to this problem were offering. I thought it would make sense to automatically create a set of input elements on the footer row. So, right after the FooterRow is identified/created, I iterate through all the columns and create the appropriate cells on the footer row.

C#
for (int i =  0;  i <  Columns.Count; i++) {
    DataControlFieldCell cell = (DataControlFieldCell)FooterRow.Cells[i];
    DataControlField fld = Columns[i];
    if (fld is CommandField) {
        CommandField cf = (CommandField)fld;
        CommandField ins = new CommandField();
        ins.ButtonType = cf.ButtonType;
        ins.InsertImageUrl = cf.InsertImageUrl;
        ins.InsertText = cf.InsertText;
        ins.CancelImageUrl = cf.CancelImageUrl;
        ins.CancelText = cf.CancelText;
        ins.InsertVisible = true;
        ins.ShowInsertButton = true;
        ins.Initialize(false, this);
        ins.InitializeCell(cell, DataControlCellType.DataCell,
                 DataControlRowState.Insert, -1);
    }
    else {
        fld.Initialize(base.AllowSorting, this);
        fld.InitializeCell(cell, DataControlCellType.DataCell,
                  DataControlRowState.Edit | DataControlRowState.Insert, -1);
    }
}

Allow for the two-way binding on the insert/footer row

One thing that I think is missing in the new DetailsView data bound control is the ability to nicely initialize the insert data. Over here, I thought it would be nice to correct this error. So, I would create a dummy DataTable and fill it up with the values for each column. Then, I call the OnRowCreated function (raise the event) to allow the application to initialize the insert data (see InsertableGrid1_RowCreated above). That is especially useful when you have a BoundField where you can't easily identify the input controls. Of course, if you have templated columns, then you can use the Row.FindControl() function since you would know the name of the control (just like you would with the DetailsView control).

C#
OrderedDictionary dict = new OrderedDictionary();
base.ExtractRowValues(dict, FooterRow, true, true);
DataTable tbl = new DataTable();
DataRow row = tbl.Rows.Add();
foreach (string k in dict.Keys) {
    tbl.Columns.Add(new DataColumn(k));
    row[k] = dict[k];
}
FooterRow.DataItem = new DataView(tbl)[0];
GridViewRowEventArgs args1 = new GridViewRowEventArgs(FooterRow);
this.OnRowCreated(args1);
FooterRow.DataBind();
this.OnRowDataBound(args1);
FooterRow.DataItem = null;
foreach (DataControlField f in Columns)
    f.Initialize(this.AllowSorting, this);

Outstanding issues

  • Can't put my finger on it, but somehow, during the design, ItemTemplate/EditTemplate comes out in lower case.
  • Would like to change the designer to draw the grid with an insert line in it to provide for visual cue.
  • The sample ASPX page works with the database on my local machine. You would need to either create the table or change the page. Once again, the configuration is identical to the GridView, so either drop and configure, or configure the GridView and then just change tags.

History

  • Apply footer styles to insert row - Changes made to set ShowFooter flags as long as AllowInsert is set. This forces the GridView to apply FooterStyle to the insert row.
  • Allow page validation to cancel insert - Added check for Page.IsValid to the OnRowCommand. Avoid insertion if failure.
  • Fixed crash with auto-increment columns - Fixed the initialization for the footer row binding to include auto-increment columns.
  • Changed the RowInserting event to GridViewUpdateEventHandler type - To prevent crash and to be more consistent. Note: this may affect compatibility with the prior version.

License

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


Written By
http://www.GaspMobileGames.com
United States United States
Writing code since 1987 using whatever language/environment you can imagine. Recently got into the mobile games. Feel free to check them out at http://www.GaspMobileGames.com

Comments and Discussions

 
QuestionCalling the Insert Method Pin
Mark Iovino11-Nov-12 15:18
Mark Iovino11-Nov-12 15:18 
Apologies for digging up an old article, but I've only just recently found this, and I have one (hopefully) simple question:

Can I make the InsertableGridView perform an Insert from another button on my form? In other words, is there similar functionality to the "UpdateRow" method?

For background, I'm trying to make the GridView react correctly when the user presses ENTER. I'd like it to trigger the "Update" or "Insert" events, depending on the GridView's mode. I've created a Button near the GridView, and wrapped both controls in a Panel. Finally, I've set the "DefaultButton" property of the Panel to the ID of the Button. So far, I can make it Update, but not Insert.

The HTML is:
ASP.NET
<asp:Panel runat="server" id="pnl" DefaultButton="btn">
    <asp:Button runat="server" id="btn" />
    <my:InsertableGridView runat="server" id="gv" ShowFooter="true" AllowInsert="true">
    </my:InsertableGridView>
</asp:Panel>

...and the VB is:
VB
Protected Sub btn_Click(sender as Object, e as EventArgs) Handles btn.Click
    With gv
        If .EditIndex = -1 Then
            ' Call GridView's Insert method, somehow.
        Else
            .UpdateRow(.EditIndex, True)
        End If
    End With
End Sub

Notes:
(1) I use a Panel's "DefaultButton" (and not the Form's "DefaultButton") because there may be multiple GridViews on the form. I'd like it to work on the Panel that has the focus.
(2) I use ".UpdateRow" so the GridView's validation gets triggered. I'd like the Insert command to do the same.

Alternatively, is there an easier way to get the GridView to react to the ENTER key?

Aside from that, great article - thanks!
AnswerRe: Calling the Insert Method Pin
gstolarov11-Nov-12 16:51
gstolarov11-Nov-12 16:51 
GeneralRe: Calling the Insert Method Pin
Mark Iovino11-Nov-12 18:24
Mark Iovino11-Nov-12 18:24 
QuestionMy vote of 5 Pin
Richard Blythe15-Mar-12 11:28
Richard Blythe15-Mar-12 11:28 
AnswerRe: My vote of 5 Pin
gstolarov15-Mar-12 11:46
gstolarov15-Mar-12 11:46 
Questionframework 4 error Pin
Member 82795213-Jan-12 18:21
Member 82795213-Jan-12 18:21 
GeneralToggling insert mode in code Pin
boxersoft16-Aug-09 9:34
boxersoft16-Aug-09 9:34 
GeneralRe: Toggling insert mode in code Pin
gstolarov17-Aug-09 4:07
gstolarov17-Aug-09 4:07 
GeneralRe: Toggling insert mode in code Pin
boxersoft17-Aug-09 6:55
boxersoft17-Aug-09 6:55 
GeneralProblem using CalendarExtender Pin
Yuliyan26-Jan-09 23:44
Yuliyan26-Jan-09 23:44 
GeneralVB Version Code [modified] Pin
malbert6921-Oct-08 10:12
malbert6921-Oct-08 10:12 
GeneralProblem with AutoGenerated buttons (solution) Pin
tjastrzebski21-Apr-08 7:01
tjastrzebski21-Apr-08 7:01 
GeneralBlank field values after handled exception Pin
dani rk2-Apr-08 5:16
dani rk2-Apr-08 5:16 
GeneralRe: Blank field values after handled exception Pin
gstolarov8-Nov-08 14:40
gstolarov8-Nov-08 14:40 
AnswerDropDownList invalid SelectedValue fix (kindof) Pin
Jethro Hoobershtanker14-Feb-08 5:56
Jethro Hoobershtanker14-Feb-08 5:56 
GeneralRe: DropDownList invalid SelectedValue fix (kindof) Pin
Felipe Teixeira18-Aug-08 3:28
Felipe Teixeira18-Aug-08 3:28 
GeneralDropdown + EditItemTemplate bug = REAL FIX IN HERE Pin
Felipe Teixeira18-Aug-08 4:32
Felipe Teixeira18-Aug-08 4:32 
GeneralRe: DropDownList invalid SelectedValue fix (kindof) Pin
gstolarov18-Aug-08 10:47
gstolarov18-Aug-08 10:47 
Questiondifferent between gridview used datasource(wizard) and the one used dataset? Pin
Spring7714-Jan-08 21:28
Spring7714-Jan-08 21:28 
GeneralCannot be used as a drop-in replacement for asp:GridView Pin
Perry29-Dec-07 2:19
Perry29-Dec-07 2:19 
QuestionSkinnable? Pin
Amy de Buitlir26-Nov-07 22:35
Amy de Buitlir26-Nov-07 22:35 
Generalinsert into DataTable using ObjectDataSource Pin
megadith14-Nov-07 4:48
megadith14-Nov-07 4:48 
AnswerA functional InsertVisible [modified] Pin
ChrisRico11-Oct-07 11:29
ChrisRico11-Oct-07 11:29 
QuestionCan I use a FooterTemplate? Pin
vlpk31-Jul-07 11:01
vlpk31-Jul-07 11:01 
QuestionNo comments? Pin
awarberg30-Jun-07 3:28
awarberg30-Jun-07 3:28 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.