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);
}