Extending DataControlField – EditableButtonField
It turns out that once you start extending DataControlField, you never turn back. I have discovered joy in reducing code duplication and creating reusable components by converting common GridView tasks into new DataControlFields. Here’s another fun one: EditableButtonField.
A “normal” ButtonField is a read-only control which has no built-in behavior when the row is being edited. With the EditableButtonField control, it will convert to a TextBox and provide immediate access to the DataTextField element. Nifty!
Note that this control simply extends ButtonField rather than extending the full DataControlField. Also note that I am assuming a ButtonType of “Link” and this would probably explode into itty bitty bits if you tried a Button.
<code>
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace JoeDonahue.resources {
public class EditableButtonField : ButtonField {
private Boolean inEditMode;
public override void InitializeCell(DataControlFieldCell cell,
DataControlCellType cellType, DataControlRowState rowState, int rowIndex) {
base.InitializeCell(cell, cellType, rowState, rowIndex);
switch (cellType) {
case DataControlCellType.DataCell:
this.InitializeDataCell(cell, rowState);
break;
case DataControlCellType.Footer:
this.InitializeFooterCell(cell, rowState);
break;
case DataControlCellType.Header:
this.InitializeHeaderCell(cell, rowState);
break;
}
}
protected void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState) {
cell.DataBinding += new EventHandler(OnDataBindField);
this.inEditMode = (rowState & (DataControlRowState.Edit | DataControlRowState.Insert)) != 0;
if (inEditMode) {
TextBox t = new TextBox();
cell.Controls.Clear();
cell.Controls.Add(t);
} else {
// Default behavior is OK
}
}
protected void InitializeHeaderCell(DataControlFieldCell cell, DataControlRowState rowState) {
}
protected void InitializeFooterCell(DataControlFieldCell cell, DataControlRowState rowState) {
}
protected virtual void OnDataBindField(object sender, EventArgs e) {
TableCell cell = (TableCell)sender;
IDataItemContainer container = (IDataItemContainer)cell.NamingContainer;
object boundvalue = GetBoundValue(container);
String selectedValue = boundvalue.ToString();
/* Set the corresponding text or selectedValue */
if (inEditMode) {
object dataItem = DataBinder.GetDataItem(container);
boundvalue = DataBinder.GetPropertyValue(dataItem, DataTextField);
selectedValue = boundvalue.ToString();
TextBox t = (TextBox)cell.Controls[0];
if (selectedValue != null && selectedValue.Length > 0)
t.Text = selectedValue;
} else {
LinkButton l = (LinkButton)cell.Controls[0];
l.Text = selectedValue;
}
}
object GetBoundValue(IDataItemContainer controlContainer) {
object dataItem = DataBinder.GetDataItem(controlContainer);
return DataBinder.GetPropertyValue(dataItem, DataTextField);
}
public override void ExtractValuesFromCell(System.Collections.Specialized.IOrderedDictionary dictionary, DataControlFieldCell cell, DataControlRowState rowState, bool includeReadOnly) {
base.ExtractValuesFromCell(dictionary, cell, rowState, includeReadOnly);
this.inEditMode = (rowState & (DataControlRowState.Edit | DataControlRowState.Insert)) != 0;
string value = null;
if (cell.Controls.Count > 0) {
Control control = cell.Controls[0];
if (control == null)
throw new InvalidOperationException(“The control cannot be extracted”);
if (inEditMode)
value = ((TextBox)control).Text;
else
value = ((LinkButton)control).Text;
}
if (dictionary.Contains(this.DataTextField))
dictionary[this.DataTextField] = value;
else
dictionary.Add(this.DataTextField, value);
}
}
}
</code>