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

NewRow GridView

, 24 Oct 2006
Rate this:
Please Sign up or sign in to vote.
A GridView component with integrated new rows (no footer/data source manipulation).

Sample Image

Introduction

Have you ever wanted to add editable rows to a GridView but didn't want the hassle with customizing the footer or manipulating the data source? If that's the case, maybe the NewRowGridView is something for you.

Using the code

Inside the demo project, you'll find several files, from which the NewRowGridView is the most important one. Here, we extend the known GridView component with extra editable rows using the GridView's own methods for creating those. We expose the newly created rows with the NewRows property. We also add a property NewRowCount which determines the number of editable rows to add to the GridView. When a user changes the data in the newly created rows, we can access those through the NewRowsChanged property.

private GridViewRowCollection _newRows;
private List< int > _changedRows;
//
[Browsable(false)]
public GridViewRowCollection NewRows
{
    get
    {
        return (this._newRows == null) ? new 
                GridViewRowCollection(new ArrayList()) : 
                this._newRows;
    }
}
//
public int NewRowCount
{
    get
    {
        object viewState = this.ViewState["NewRowCount"];
        return (viewState == null) ? 0 : (int)viewState;
    }
    set { this.ViewState["NewRowCount"] = value; }
}
//
[Browsable(false)]
public GridViewRowCollection NewRowsChanged
{    
    get
    {
        if (this._changedRows != null)
        {
            ArrayList changedRows = new ArrayList();
                  
            foreach (int rowIndex in this._changedRows)
            {
                changedRows.Add(this._newRows[rowIndex]);
            }
            return new GridViewRowCollection(changedRows);
        }
        return new GridViewRowCollection(new ArrayList());
    }
}

For creating rows, we'll be using the GridView's CreateRow and InitializeRow methods. The CreateRow method expects, amongst others, the DataControlRowState property. By setting this to Insert, the row will be initialized with editable components like a TextBox or a CheckBox. The data information will be collected through the GetDataFields method.

private DataControlField[] GetDataControlFields()
{
    DataControlField[] fields = 
        new DataControlField[this.Columns.Count];
    base.Columns.CopyTo(fields, 0);
    return fields;
}
//
private GridViewRow CreateNewRow(int rowIndex, DataControlField[] fields)
{
    GridViewRow newRow = base.CreateRow(rowIndex, -1, 
                         DataControlRowType.DataRow, 
                         DataControlRowState.Insert);
    base.InitializeRow(newRow, fields);
    this.AddRowChanged(newRow);
    return newRow;
}

The AddRowChanged method adds an event handler to the newly created controls within the new row which fires when the state of these controls change. We then add the RowIndex of the new row to the _changedRow list for further reference.

private void AddRowChanged(Control control)
{
    foreach (Control ctr in control.Controls)
    {
        if (ctr is TextBox)
        {
            ((TextBox)ctr).TextChanged += 
               new EventHandler(this.RowChanged);
        }
        else if (ctr is ListControl)
        {
            ((ListControl)ctr).SelectedIndexChanged += 
                    new EventHandler(this.RowChanged);
        }
        else if (ctr is CheckBox)
        {
            ((CheckBox)ctr).CheckedChanged += 
              new EventHandler(this.RowChanged);
        }

        if (ctr.HasControls())
        {
            this.AddRowChanged(ctr);
        }
    }
}

private void RowChanged(object sender, EventArgs e)
{
    GridViewRow row = 
       (GridViewRow)((Control)sender).NamingContainer;

    if (this._changedRows == null)
    {
        this._changedRows = new List< int >();
    }

    if (!this._changedRows.Contains(row.RowIndex))
    {
        this._changedRows.Add(row.RowIndex);
    }
}

The GridView, when rendered to the browser, is basically nothing more than a Table. We can find the table by calling the Parent property of one of the rows, or in case of no data, we create our own by calling the CreateChildTable method of the GridView. In the latter case, we also have to add the table to the GridView's ControlCollection. Another point of interest: if there's no data (rows), the GridView will automatically hide the header and footer. In that case, we have to create a header row in the same way we created an insertable row, except that the DataControlRowState property is set to Normal.

private void CreateRows()
{
    if (this.NewRowCount > 0)
    {
        ArrayList list = new ArrayList();
        DataControlField[] fields = this.GetDataControlFields();
        for (int i = 0; i < this.NewRowCount; i++)
        {
            GridViewRow newRow = this.CreateNewRow(i, fields);
            list.Add(newRow);
        }
        this._newRows = new GridViewRowCollection(list);

        Table grid;
        if (this.Rows.Count == 0)
        {
            grid = this.CreateChildTable();
            this.Controls.Add(grid);
            if (this.ShowHeader)
            {
                GridViewRow headerRow = 
                   this.CreateHeaderRow(fields);
                grid.Rows.Add(headerRow);
            }
        }
        else
        {
            grid = (Table)this.Rows[0].Parent;
        }

        int rowIndex = this.Rows.Count + 1;
        foreach (GridViewRow newRow in this._newRows)
        {
            grid.Rows.AddAt(rowIndex, newRow);
            rowIndex++;
        }
    }
}

private GridViewRow CreateHeaderRow(DataControlField[] fields)
{
    GridViewRow headerRow = base.CreateRow(-1, -1, 
        DataControlRowType.Header, DataControlRowState.Normal);
    base.InitializeRow(headerRow, fields);
     
    return headerRow;
}

The last step is to call the CreateRows method. Therefore, we have to override the CreateChildControls method.

protected override int CreateChildControls(IEnumerable 
                       dataSource, bool dataBinding)
{
    int rowCount = base.CreateChildControls(dataSource, 
                                            dataBinding);
    this.CreateNewRows();
    return rowCount;
}

That's it! Now you can access the new values through the NewRows collection, and the changed values through the NewRowsChanged collection.

License

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

About the Author

Erik_D
Web Developer
Netherlands Netherlands
No Biography provided

Comments and Discussions

 
QuestionHow to set the NewRowCount dynamically Pinmemberlakshmimnl9-Aug-09 15:58 
General"Fix" for using databound DropDownList in grid PinmemberSteve Yates13-Mar-07 9:40 
GeneralLooks nice, but can't be used by anyone else PinmemberLaBlua7-Feb-07 8:27 
GeneralNice control, but CSS Friendly adapters will break it PinmemberAxleMunshine20-Dec-06 12:48 
QuestionHow to add the row dynamic and eidt it Pinmemberdongxiang23-Nov-06 14:02 
AnswerRe: How to add the row dynamic and eidt it PinmemberErik_D29-Nov-06 2:25 
GeneralNice coding! PinmemberDenzel31-Oct-06 2:45 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 24 Oct 2006
Article Copyright 2006 by Erik_D
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid