Extending ASP.NET: EditableHyperLinkField

Over the years of coding in ASP.NET, I continue to find ways to create simple, reusable objects that are fun and make development easier.  One of my favorite ways is extending the DataBound objects that are used in GridViews and DetailsViews.  I’ve already offered up DropDownField, which I use over and over again. I have a few more that are great to use in GridView scenarios that provide a better User Experience and less coding. Win! Today’s freebie is: EditableHyperLinkField.

A common scenario with GridViews is a list of records: It will contain an id and a name, as well as links to Edit, Delete, and Select the item to get more info. This gives you a quaint little usable-but-ugly table which is great to Tutorials but not exactly something you’re going to hand in to the Corner Office.

editablehyperlinkfield_1

But, at least it has the handy-dandy inline edit function, right? I mean, right?

editablehyperlinkfield_2

One of the ugliest components is the unnecessary “Select” link. The name of the record itself should be the link, and the rightmost column can be exterminated. Only one problem: HyperLinkFields do not play nicely with GridView’s inline editing. When editing a row, the HyperLinkField remains readonly. In this example, only the ID field changes (which under normal circumstances would be set to readonly also to avoid Data Integrity violation).

editablehyperlinkfield_3

Aggh! Settle down now.  The solution is to introduce a new object, EditableHyperLinkField, which extends the normal HyperLinkField and adds the desired compatibility with inline editing. Check it out!

 

editablehyperlinkfield_4

Now we are closer to a GridView we can actually use!

Oh, you’d like to see the code?


using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace MyProject.resources {
public class EditableHyperLinkField : HyperLinkField {

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 {
HyperLink l = (HyperLink)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 = ((HyperLink)control).Text;

}

if (dictionary.Contains(this.DataTextField))
dictionary[this.DataTextField] = value;
else
dictionary.Add(this.DataTextField, value);
}
}

}

Leave a Reply

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