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

GridView with insert line

By , 1 Jun 2007
 

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:

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.

    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.

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).

    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)

About the Author

gstolarov
United States United States
Member
No Biography provided

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   
QuestionCalling the Insert MethodmemberMark 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: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:
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 Methodmembergstolarov11 Nov '12 - 16:51 
I kind of moved on too and published another article jQuery Based Ajax.Net library[^] Over there I switch from one row to another based on where user clicks (using jQuery). Please download that file and see jquery.tabs.js file $.fn.Grid plugin around line 105 - it might give you some idea.
GeneralRe: Calling the Insert MethodmemberMark Iovino11 Nov '12 - 18:24 
Thanks for your response. I'll check it out.
 
Looks like I can make use of some of your other controls, too! Big Grin | :-D
QuestionMy vote of 5memberRichard Blythe15 Mar '12 - 11:28 
Great job my friend!
Be nice to your kids. They'll choose your nursing home.

My Articles
   Developer's Best Friend

AnswerRe: My vote of 5membergstolarov15 Mar '12 - 11:46 
I did some updates and published this control along with other useful staff at jQuery Based Ajax.Net library[^] If you are planning to use it give this article a try.
Questionframework 4 errormemberMember 82795213 Jan '12 - 18:21 
I used this great control for years, but now with framework 4 i have some problems with insert event. The specific error is that after insert a record in gridview is launched event of container form. Tis behavior is only in framework 4
Any Ideas?
Thanks
GeneralToggling insert mode in codememberboxersoft16 Aug '09 - 9:34 
Hi, just found this and it seems like a neat solution. I wanted to make the grid read-only by default and have an "add new" button that would perform a postback and set AllowInsert=True. I can't get it to work though. If I set AllowInsert=True at design-time it works as expected. If I set it in an event handler though (e.g. in grid_Init), the insertable row isn't rendered. I'm not very familiar with ASP so perhaps my understaanding of page lifecycles etc. is at the root of my problem. Is there a particular event handler that I should target?
GeneralRe: Toggling insert mode in codemembergstolarov17 Aug '09 - 4:07 
I strongly encourage you to use later version of the library described in jQuery Based Ajax.Net library[^]. In general however all the controls are created in the CreateControls and doing it in event handler is too late. The easiest thing is to set grid.Footer.Visible = false.
GeneralRe: Toggling insert mode in codememberboxersoft17 Aug '09 - 6:55 
Thanks, I'll take a look at the version you mention.
 
doing it in event handler is too late

 
If in Page_Load I just do:
 

If IsPostback Then
grid.AllowInsert = True
End If

 
... and I provoke a Postback by clicking a Sort header, it works. It doesn't work if the Postback is caused by clicking a Button control though. I'm not yet sure why this is.
GeneralProblem using CalendarExtendermemberYuliyan26 Jan '09 - 23:44 
Hi all,
 
My code:

<asp:textbox id="DateTextBox" width="70px" runat="server" text="<%# Bind("Date") %>" onload="DateTextBox_Load" xmlns:asp="#unknown">

<asp:image id="Image1" runat="server" imageurl="Images/Calendar_scheduleHS.png" xmlns:asp="#unknown">

<cc1:calendarextender id="CalendarExtender1" format="dd.MM.yyyy" runat="server" targetcontrolid="DateTextBox" popupbuttonid="Image1" xmlns:cc1="#unknown">

<asp:requiredfieldvalidator id="DateRequiredFieldValidator" runat="server" controltovalidate="DateTextBox" errormessage="Date is required!" xmlns:asp="#unknown">

 
couse System.InvalidOperationException "Extender controls may not be registered before PreRender."
 
StackTrace:
at System.Web.UI.ScriptControlManager.RegisterExtenderControl[TExtenderControl](TExtenderControl extenderControl, Control targetControl)
at System.Web.UI.ScriptManager.RegisterExtenderControl[TExtenderControl](TExtenderControl extenderControl, Control targetControl)
at System.Web.UI.ExtenderControl.RegisterWithScriptManager()
at System.Web.UI.ExtenderControl.OnPreRender(EventArgs e)
at AjaxControlToolkit.ExtenderControlBase.OnPreRender(EventArgs e) in D:\tools\ASP_Ajax\AjaxControlToolkit\ExtenderBase\ExtenderControlBase.cs:line 367
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
 
Can someone help me?
GeneralVB Version Code [modified]membermalbert6921 Oct '08 - 10:12 
I have converted the C# to VB for anyone interested... Enjoy.
 
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Drawing.Design
Imports System.Collections.Specialized
Imports System.Data
 
Namespace InsGrid
    <DefaultEvent("SelectedIndexChanged")> _
    <SupportsEventValidation()> _
    <Designer("System.Web.UI.Design.WebControls.GridViewDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")> _
    <ControlValueProperty("SelectedValue")> _
    <ToolboxData("<{0}:InsertableGrid runat="server"></{0}:InsertableGrid>")> _
    Public Class InsertableGrid
        Inherits GridView
 
        <Category("Action")> _
        Public Event RowInserted(ByVal sender As Object, ByVal e As GridViewUpdatedEventArgs)
 
        <Category("Action")> _
        Public Event RowInserting(ByVal sender As Object, ByVal e As GridViewUpdateEventArgs)
 
        <Browsable(True), DefaultValue("true"), Category("Behavior")> _
        Public Property AllowInsert() As Boolean
            Get
                Return CBool(IIf(ViewState("_InsOk") Is Nothing, True, CBool(ViewState("_InsOk"))))
            End Get
            Set(ByVal Value As Boolean)
                ViewState("_InsOk") = Value
            End Set
        End Property
 
        <Browsable(True), DefaultValue("false"), Category("Behavior")> _
        Public Property SuppressReadOnlyColumns() As Boolean
            Get
                Return CBool(IIf(ViewState("_SupRO") Is Nothing, False, CBool(ViewState("_SupRO"))))
            End Get
            Set(ByVal Value As Boolean)
                ViewState("_SupRO") = Value
            End Set
        End Property
 
        Private _InsertValues As IOrderedDictionary = Nothing
        Protected Property InsertValues() As IOrderedDictionary
            Get
                Return _InsertValues
            End Get
            Set(ByVal Value As IOrderedDictionary)
                _InsertValues = Value
            End Set
        End Property
 
        Protected gvFooterRow As GridViewRow = Nothing
        Public Overrides ReadOnly Property FooterRow() As GridViewRow
            Get
                Return CType(IIf(gvFooterRow Is Nothing, MyBase.FooterRow, gvFooterRow), GridViewRow)
            End Get
        End Property
 
        <Browsable(True)> _
        Public Overrides ReadOnly Property Columns() As DataControlFieldCollection
            Get
                Return MyBase.Columns
            End Get
        End Property
 
        Protected Overrides Function CreateChildControls(ByVal dataSource As System.Collections.IEnumerable, ByVal dataBinding As Boolean) As Integer
            Dim ret As Integer = MyBase.CreateChildControls(dataSource, dataBinding)
            If Columns.Count = 0 Or DesignMode Or Not AllowInsert Then
                Return ret
            End If
            ShowFooter = True
            Dim flds() As DataControlField = New DataControlField(Columns.Count - 1) {}
            Columns.CopyTo(flds, 0)
            If ret = 0 Then
                Controls.Clear()
                Dim t As Table = New Table()
                Controls.Add(t)
 
                Dim r As GridViewRow = CreateRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal)
                Me.InitializeRow(r, flds)
                t.Rows.Add(r)
 
                gvFooterRow = CreateRow(-1, -1, DataControlRowType.Footer, DataControlRowState.Insert)
                Me.InitializeRow(gvFooterRow, flds)
                t.Rows.Add(gvFooterRow)
            Else
                gvFooterRow = MyBase.FooterRow
            End If
            FooterRow.RowState = DataControlRowState.Insert
            FooterRow.Visible = (MyBase.EditIndex < 0)
            For i As Integer = 0 To Columns.Count - 1
                Dim cell As DataControlFieldCell = CType(FooterRow.Cells(i), DataControlFieldCell)
                Dim fld As DataControlField = Columns(i)
                Dim NotReadOnly As Boolean = True
                If (Me.SuppressReadOnlyColumns) Then
                    If (Columns(i).GetType().Name.EndsWith("BoundField")) Then
                        NotReadOnly = Not (CType(Columns(i), BoundField)).ReadOnly
                    ElseIf (Columns(i).GetType().Name.EndsWith("CheckBoxField")) Then
                        NotReadOnly = Not (CType(Columns(i), CheckBoxField)).ReadOnly
                    ElseIf (Columns(i).GetType().Name.EndsWith("ImageField")) Then
                        NotReadOnly = Not (CType(Columns(i), ImageField)).ReadOnly
                    End If
                End If
                fld.InsertVisible = (fld.Visible And NotReadOnly)
                If TypeOf fld Is CommandField Then
                    Dim cf As CommandField = CType(fld, CommandField)
                    Dim ins As CommandField = New CommandField()
                    ins.ButtonType = cf.ButtonType
                    ins.InsertImageUrl = cf.InsertImageUrl
                    ins.InsertText = cf.InsertText
                    ins.CancelImageUrl = cf.CancelImageUrl
                    ins.CancelText = cf.CancelText
                    ins.ValidationGroup = cf.ValidationGroup
                    ins.CausesValidation = cf.CausesValidation
                    ins.InsertVisible = True
                    ins.ShowInsertButton = True
                    ins.Initialize(False, Me)
                    ins.InitializeCell(cell, DataControlCellType.DataCell, DataControlRowState.Insert, -1)
                ElseIf cell.Controls.Count = 0 Then
                    fld.Initialize(MyBase.AllowSorting, Me)
                    If NotReadOnly Then
                        fld.InitializeCell( _
                                cell, _
                                DataControlCellType.DataCell, _
                                CType(DataControlRowState.Edit + DataControlRowState.Insert, DataControlRowState), _
                                -1)
                    End If
                End If
            Next
            Dim dict As OrderedDictionary = New OrderedDictionary()
            MyBase.ExtractRowValues(dict, FooterRow, True, True)
            Dim tbl As DataTable = New DataTable()
            Dim row As DataRow = tbl.Rows.Add()
            For Each k As String In dict.Keys
                tbl.Columns.Add(New DataColumn(k))
                row(k) = dict(k)
            Next
            FooterRow.DataItem = New DataView(tbl).Item(0)
            Dim args1 As GridViewRowEventArgs = New GridViewRowEventArgs(FooterRow)
            Me.OnRowCreated(args1)
            FooterRow.DataBind()
            Me.OnRowDataBound(args1)
            FooterRow.DataItem = Nothing
            For Each f As DataControlField In Columns
                f.Initialize(Me.AllowSorting, Me)
            Next
            Return ret
        End Function
 
        Protected Overridable Sub OnRowInserting(ByVal e As GridViewUpdateEventArgs)
            RaiseEvent RowInserting(Me, e)
        End Sub
 
        Protected Overridable Sub OnRowInserted(ByVal e As GridViewUpdatedEventArgs)
            RaiseEvent RowInserted(Me, e)
        End Sub
 
        Protected Overrides Sub OnRowCommand(ByVal e As GridViewCommandEventArgs)
            If "-1".Equals(e.CommandArgument) And "Cancel".CompareTo(e.CommandName) = 0 Then
                Page.Trace.Warn("Canceling insert...")
                Return
            End If
            If "-1".Equals(e.CommandArgument) And "Insert".Equals(e.CommandName) Then
                Dim args As GridViewUpdateEventArgs = New GridViewUpdateEventArgs(-1)
                MyBase.ExtractRowValues(args.NewValues, FooterRow, True, True)
                InsertValues = args.NewValues
                Dim allEmpty As Boolean = True
                For Each v As Object In InsertValues.Values
                    If v IsNot Nothing AndAlso System.Convert.ToString(v).Trim().Length > 0 Then
                        allEmpty = False
                        Exit For
                    End If
                Next
                If allEmpty Then
                    Return
                End If
                Me.OnRowInserting(args)
                If args.Cancel Then
                    Return
                End If
                Dim view As DataSourceView = Me.GetData()
                view.Insert(args.NewValues, New System.Web.UI.DataSourceViewOperationCallback(AddressOf CallBack))
                Return
            End If
            MyBase.OnRowCommand(e)
        End Sub
 
        Private Function CallBack(ByVal affectedRows As Integer, ByVal ex As Exception) As Boolean
            Dim evt As GridViewUpdatedEventArgs = New GridViewUpdatedEventArgs(affectedRows, ex)
            evt.NewValues.Clear()
            For Each v As String In InsertValues.Keys
                evt.NewValues.Add(v, InsertValues(v))
            Next
            Me.OnRowInserted(evt)
            If ex Is Nothing And Not evt.ExceptionHandled Then
                Return False
            End If
            MyBase.RequiresDataBinding = True
            Return True
 
        End Function
    End Class
End Namespace

 
modified on Tuesday, February 3, 2009 9:50 AM

GeneralProblem with AutoGenerated buttons (solution)membertjastrzebski21 Apr '08 - 7:01 
Man, awesome job!
I found just one problem: the code does not take AutoGenerated buttons under consideration - they cause off-by-one error and the grid does not render the way it should. Here is my solution (tested). Modify InsertableGrid.cs file as follows:
lines 60-62
was:

DataControlField[] flds = new DataControlField[Columns.Count];
Columns.CopyTo(flds, 0);
if (ret == 0) {
correction:
if (ret == 0) {
	bool hasAutoCommandField = base.AutoGenerateDeleteButton || base.AutoGenerateEditButton || base.AutoGenerateSelectButton;
	int autoCommandFieldOffset = hasAutoCommandField ? 1 : 0;
	DataControlField[] flds = new DataControlField[Columns.Count + autoCommandFieldOffset];
	if (hasAutoCommandField) flds[0] = new CommandField();
	Columns.CopyTo(flds, autoCommandFieldOffset);
lines 79-81:
was:

for (int i = 0; i < Columns.Count; i++) {
	DataControlFieldCell cell = (DataControlFieldCell)FooterRow.Cells[i];
	DataControlField fld = Columns[i];
correction:
for (int i = 0; i < FooterRow.Cells.Count; i++) {
	DataControlFieldCell cell = (DataControlFieldCell)FooterRow.Cells[i];
	DataControlField fld = cell.ContainingField;
 
Cheers,
 
Thomas Jastrzebski
GeneralBlank field values after handled exceptionmemberddddddaaa2 Apr '08 - 5:16 
Very nice solution!
 
Question:
 
If inserting to DB caused an exception, it can be handled in InsertableGrid1_RowInserted.
 
But even if (GridViewUpdatedEventArgs)eventArgs.KeepInEditMode is set to true, the old values that caused the error are cleared.
 
This is annoying if a lot of data has been entered before Insert and the action fails on only one of them.
 
Is it possible to have similar behavior as setting (GridViewUpdatedEventArgs)eventArgs.KeepInEditMode in normal edit mode?
 

Dani
GeneralRe: Blank field values after handled exceptionmembergstolarov8 Nov '08 - 14:40 
I also encountered this problem. Has to with me rebinding after insertion whether there was an error or not. I fixed this problem and expanded the library. Check this article: http://www.codeproject.com/KB/ajax/jqueryajax.aspx[^]
AnswerDropDownList invalid SelectedValue fix (kindof)memberJethro Hoobershtanker14 Feb '08 - 5:56 
Hi, thanks again for a great gridview! If anyone else is getting this error (using a databound DropDownList in your EditItemTemplate), try:
 
Add this to the InsertableGrid code:
 
private void PrepareDropDowns(bool addBlank)
{
foreach (TableCell t in FooterRow.Cells)
{
foreach (Control c in t.Controls)
{
DropDownList ddl = c as DropDownList;
 
if (ddl != null && !ddl.DataSourceID.Equals(""))
{
if (addBlank)
{
ddl.AppendDataBoundItems = true;
ddl.Items.Insert(0, "");
}
else
{
ddl.SelectedIndex = 1;
ddl.Items.RemoveAt(0);
}
}
}
}
}

 
Swap your CreateChildControls routine to this:
 
protected override int CreateChildControls(System.Collections.IEnumerable dataSource, bool dataBinding)
{
int ret = base.CreateChildControls(dataSource, dataBinding);
if (Columns.Count == 0 || DesignMode || !AllowInsert)
return ret;
ShowFooter = true;
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;
FooterRow.RowState = DataControlRowState.Insert;
FooterRow.Visible = (base.EditIndex < 0);
for (int i = 0; i < Columns.Count; i++)
{
DataControlFieldCell cell = (DataControlFieldCell)FooterRow.Cells[i];
DataControlField fld = Columns[i];
fld.InsertVisible = fld.Visible;
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 if (cell.Controls.Count == 0)
{ //don't overwrite any existing controls
fld.Initialize(base.AllowSorting, this);
fld.InitializeCell(cell, DataControlCellType.DataCell, DataControlRowState.Edit | DataControlRowState.Insert, -1);
PrepareDropDowns(true);
}
}
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);
PrepareDropDowns(false);
return ret;
}

 
Cheers
GeneralRe: DropDownList invalid SelectedValue fix (kindof)memberFelipe Teixeira18 Aug '08 - 3:28 
Hello there!
 
For some reason this is not working for me.. any ideas? I've just copy/paste your code with no success...
 
Best Regards
GeneralDropdown + EditItemTemplate bug = REAL FIX IN HEREmemberFelipe Teixeira18 Aug '08 - 4:32 
my problem is solved.
 
I just ripped your function out of my code and started using the one I found at: http://forums.asp.net/p/755961/1012665.aspx[^] in the post by BurntSky.
 
Thank you anyway and hope it helps Big Grin | :-D
GeneralRe: DropDownList invalid SelectedValue fix (kindof)membergstolarov18 Aug '08 - 10:47 
I think the problem here is when I'm trying to create an insert line, I'm trying to bind it to the data. The reason it was done is so I can fill up the insert line with default values. During the binding, list control tries to select empty data in the drop down list box. There are couple of ways to solve it:
- Create OnRowCreated event handler and initialize insert data in there (see article for details on how to do it).
- Remove portion that tries to bind footer row to the data in the CreateChildControls
Questiondifferent between gridview used datasource(wizard) and the one used dataset?memberSpring7714 Jan '08 - 21:28 
hi every one
 
we can a lot of way for showing data in gridview.
1) the first one is using datasource whitout writing any code.
2) another one is using dataset,datareader,... and writing code.
 
I whant to khow that :
 
what is different between using wizard and writing code ?
when we can use the first one ?
 
thanks alot
GeneralCannot be used as a drop-in replacement for asp:GridViewmemberPerry29 Dec '07 - 2:19 
I tried using this as a drop-in replacement for asp:GridView -- just compile, add assembly, add assembly reference, and change tag type -- and it fails.
 
The CreateChildControls override fails to handle asp:HyperLink inside of ItemTemplate inside of asp:TemplateField.
 
I'm not sure whether this code breaks a naming container, or if its casts to DataControlField don't handle asp:HyperLinks, or what -- but, anyway, it appears that it is not ready to replace asp:GridView.

QuestionSkinnable?memberAmy de Buitlir26 Nov '07 - 22:35 
This is almost exactly what I need... except that when I tried it out it ignores the SkinID attribute. Did I do something wrong?
Generalinsert into DataTable using ObjectDataSourcemembermegadith14 Nov '07 - 4:48 
Hi,
 
cool control. I have it up and on my page but when I try to add to my DataSet's dataTable, it won't insert correctly. I'm using an ObjectDataSource to bind them and using the wizard to configure the SELECT and INSERT, but its still not working correctly, i just get an empty table back. When i check the RowInserting event, the data is there to send but nothign is happing. any help?
 
thanks!
 

AnswerA functional InsertVisible [modified]memberChrisRico11 Oct '07 - 11:29 
So after much pulling out of hair and gnashing of teeth, I think I found a way to use the InsertVisible property to JUST control whether or not the field is displayed in insert mode. Well, except for in a TemplateField.
 
As a reference, italic means existing code, bold means new code, and strikethrough means that it was replaced by the bold code immediately proceeding it.
 
I forgot something important
Comment out this line:
fld.InsertVisible = fld.Visible;
First, make these changes:
else if (cell.Controls.Count == 0)
{//don't overwrite any existing controls
	fld.Initialize(base.AllowSorting, this);
	fld.InitializeCell(cell, DataControlCellType.DataCell, DataControlRowState.Edit | DataControlRowState.Insert, -1);
	fld.InitializeCell(cell, DataControlCellType.DataCell, fld.InsertVisible ? DataControlRowState.Edit | DataControlRowState.Insert : DataControlRowState.Normal, -1);
}
What this does is initialize a cell to Insert mode if InsertVisible is true, or to Normal mode if it's false.
 
The next change to make:
base.ExtractRowValues(dict, FooterRow, true, true);
foreach (DataControlField f in Columns)
{
	BoundField b = f as BoundField;
	if (b != null && !dict.Contains(b.DataField))
		dict.Insert(0, b.DataField, null);
}
Because of how ExtractRowValues works, if a field is marked InsertVisible="False", the field doesn't make it into that dictionary. However, the dictionary needs to contain the field so the row can databind. Important note: I only handled for BoundFields here, you'll need to do the same thing for any other type of fields you're using. TemplateFields don't have a DataField property, obviously, so I'm not sure how you'd handle those.
 
The last change you'll need to make:
base.ExtractRowValues(args.NewValues, FooterRow, true, true);
InsertValues = args.NewValues;
foreach (DataControlField f in Columns)
{
	BoundField b = f as BoundField;
	if (b != null && !b.InsertVisible && InsertValues.Contains((string)b.DataField))
		InsertValues.Remove((string)b.DataField);
}
This is the opposite of the last problem. I'm having a brain fart at the moment so I can't remember why it happens, but when inserting, you don't want parameters created for fields marked InsertVisible="False". This takes them out.
 
Now, this whole thing could be done better if the ExtractRowValues (actually, the part that contains the code that breaks when InsertVisible is set is in the individual field type classes in a function called ExtractValuesFromCell I believe), but I didn't feel like doing that, and this was pretty easy.
 
Hope this helps.
 
Chris
QuestionCan I use a FooterTemplate?membervlpk31 Jul '07 - 11:01 
This code is absolutely amazing! It saved me a lot of work, thanks for the posting.
 
I like the fact that the footer row gets created automatically by looking at the edit row. However, I need to be able to have different fields in the footer row with extra buttons. I tried creating the FooterTemplate and it renders correctly. When I click on the insert link however, it does not insert the row and it does not fire the RowInserting event.
 
Thanks Smile | :)
QuestionNo comments?memberawarberg30 Jun '07 - 3:28 
Hello
 
I have tried in vain to add your insertion footer code to my subclassed gridview. There are multiple errors eg. the footer is not show, columns go missing and cannot be databound...
 
In trying to find the issue I see that you have exactly 0 comments in InsertableGrid.cs.
 
Admittedly, c# is easy to understand but usually you add comments to give other programmers a hint on what you are trying to do -- the big picture.
 
Normally I evaluate code quality by the (precense) and quality of the comments, among other things. While you have no comments at all the code seems pretty well worked. However it still won't play nicely with my existing app...
 
Could you please add comments in the future?
 
Best regards
Andreas Warberg

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 1 Jun 2007
Article Copyright 2006 by gstolarov
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid