ASP.NET: Writing a Custom DataControlField

I recently needed to display data in a tabular form, where all rows could be edited at once (e.g. not using the DataControlRowState.Edit functionality normally used in a gridview) If you are creating the gridview directly on an aspx page or ascx control, you can simply setup the itemtemplate for a field (e.g. to contain your custom controls):

<asp:GridView ID=”GridView1″ runat=”server” AutoGenerateColumns=”false”>
    <Columns>
        <asp:TemplateField HeaderText=”Name”>
            <ItemTemplate>
                <asp:TextBox Runat=”server” Text='<%# Bind(“name”) %>’ ID=”TextBox1″></asp:TextBox>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

This is only appropriate if you have a design surface (i.e. on an ascx or aspx page) and there are many cases where you need to create controls via code (e.g. when creating a control library, or a webpart). To create custom template fields programmatically, you must create a class deriving from System.Web.UI.WebControls.DataControlField. The code below gives an example (note that this also works with SPGridView):

public class DropDownTest : DataControlField
{
    #region Properties
    /// <summary>
    /// The name of the DataField that will be bound
    /// </summary>
    public string DataField
    {
        get
        {
            object dataField = ViewState[“DataField”];
            if  (dataField != null)
            {
                return dataField.ToString();
            }
            return string.Empty;
        }
        set
        {
            this.ViewState[“DataField”] = value;
        }
    }
    #endregion

    #region Overidden methods
    /// <summary>
    /// Returns and instance of this field
    /// </summary>
    /// <returns>DropDownTest</returns>
    protected override DataControlField CreateField()
    {
        return new DropDownTest();
    }

    /// <summary>
    /// Initialise the cell and setup binding event
    /// </summary>
    /// <param name=”cell”>Container cell</param>
    /// <param name=”cellType”>Type of cell</param>
    /// <param name=”rowState”>Row state</param>
    /// <param name=”rowIndex”>Row index</param>
    public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex)
    {
        base.InitializeCell(cell, cellType, rowState, rowIndex);
        if (cellType == DataControlCellType.DataCell)
        {
            DropDownList dropDown = new DropDownList();
            dropDown.Items.Add(“Not Visible”);
            dropDown.Items.Add(“Date”);
            dropDown.Items.Add(“Text”);
            dropDown.Items.Add(“Select”);
            cell.Controls.Add(dropDown);

            if (!string.IsNullOrEmpty(this.DataField) && this.Visible)
            {
                dropDown.DataBinding += new EventHandler(dropDown_DataBinding);
            }
        }
    }

    /// <summary>
    /// Stores the cells values
    /// </summary>
    /// <param name=”dictionary”></param>
    /// <param name=”cell”></param>
    /// <param name=”rowState”></param>
    /// <param name=”includeReadOnly”></param>
    public override void ExtractValuesFromCell(System.Collections.Specialized.IOrderedDictionary dictionary, DataControlFieldCell cell, DataControlRowState rowState, bool includeReadOnly)
    {
        base.ExtractValuesFromCell(dictionary, cell, rowState, includeReadOnly);
        string value = null;

        if (cell.Controls.Count > 0)
        {
            value = ((DropDownList)cell.Controls[0]).SelectedValue;
        }

        //If the key exists, update the value
        if (dictionary.Contains(this.DataField))
        {
            dictionary[this.DataField] = value;
        }
        //Add a new entry to the dictionary
        else
        {
            dictionary.Add(this.DataField, value);
        }
    }
    #endregion

    #region Event Handlers
    /// <summary>
    /// Perform the databinding
    /// </summary>
    /// <param name=”sender”>Sender object</param>
    /// <param name=”e”>Event args</param>
    private void dropDown_DataBinding(object sender, EventArgs e)
    {
        if (sender is DropDownList)
        {
            DropDownList dropDown = (DropDownList)sender;
            object dataItem = DataBinder.GetDataItem(dropDown.NamingContainer);
            dropDown.SelectedValue = DataBinder.GetPropertyValue(dataItem, this.DataField, null);
        }
    }
    #endregion
}

To add a custom column your gridview, simple do the following:

DropDownTest dropDownBound = new DropDownTest();
dropDownBound.DataField = “displayType”;
GridView1.Columns.Add(dropDownBound);

Note that you can obtain values by doing the following on a button click event or similar:

foreach (GridViewRow row in GridView1.Rows)
{
    string test = ((DropDownList)row.Cells[0].Controls[0]).SelectedValue;
    this.Context.Response.Write(test);
}

You May Also Like

About the Author: rnowik

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.