HOW TO – Creando nuestro propio DataControlField
Revisando unos WireFrames que se le han entregado al cliente y cuyos WebParts los estoy desarrollando yo, me he encontrado en unos de ellos que se quería mostrar una imagen en la celda de un SPGridView para que el usuario al situarse sobre ella le muestre un texto descriptivo que se carga de una propiedad.
No tendría que haber ningún problema, usamos un ImageField y listo, no? pero:
¿Y sí necesitamos añadirle un ToolTip con el valor de otra propiedad del DataBinder?
¿Y sí además en el DataBinder no existe dicha imagen como enlace de datos?
La solución: que tenemos que crearnos el nuestro propio. Así que vamos a ver como nos crearnos nuestro propio DataControlField. Para empezar lo primero es heredar de la clase DataControlField
public class ExtendedImageField : DataControlField
Una vez hecho podemos agregar nuestras propiedades (Si las necesitamos):
#region Propiedades
/// <summary>
/// Gets or sets the image URL.
/// </summary>
/// <value>The image URL.</value>
public string ImageUrl
{
get { return _imageUrl; }
set { _imageUrl = value; }
}
/// <summary>
/// Gets or sets the name of the property.
/// </summary>
/// <value>The name of the property.</value>
public string PropertyName
{
get { return _propertyName; }
set { _propertyName = value; }
}
#endregion
En mi caso. estas propiedades son para poner una imagen al control y de que propiedad del DataBinder queremos obtener información para ponerla en el ToolTip.
A continuación necesitamos sobreescribir 2 métodos. El primero CreateField:
/// <summary>
/// When overridden in a derived class, creates an empty <see cref="T:System.Web.UI.WebControls.DataControlField"/>-derived object.
/// </summary>
/// <returns>
/// An empty <see cref="T:System.Web.UI.WebControls.DataControlField"/>-derived object.
/// </returns>
protected override DataControlField CreateField()
{
return new ExtendedImageField();
}
para devolver nuestro tipo (ExtendedImageField) y acto seguido sobreescribimos InitializeCell y creamos un evento:
/// <summary>
/// Adds text or controls to a cell's controls collection.
/// </summary>
/// <param name="cell">A <see cref="T:System.Web.UI.WebControls.DataControlFieldCell"/> that contains the text or controls of the <see cref="T:System.Web.UI.WebControls.DataControlField"/>.</param>
/// <param name="cellType">One of the <see cref="T:System.Web.UI.WebControls.DataControlCellType"/> values.</param>
/// <param name="rowState">One of the <see cref="T:System.Web.UI.WebControls.DataControlRowState"/> values, specifying the state of the row that contains the <see cref="T:System.Web.UI.WebControls.DataControlFieldCell"/>.</param>
/// <param name="rowIndex">The index of the row that the <see cref="T:System.Web.UI.WebControls.DataControlFieldCell"/> is contained in.</param>
public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex)
{
base.InitializeCell(cell, cellType, rowState, rowIndex);
if (cellType == DataControlCellType.DataCell)
{
cell.DataBinding += new EventHandler(OnBindingField);
}
}
/// <summary>
/// Called when [binding field].
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
private void OnBindingField(object sender, EventArgs e)
{
Control target = (Control)sender;
TableCell tCell = target as TableCell;
if (tCell != null)
{
tCell.Attributes.Add("valign", "center");
object dataItem = DataBinder.GetDataItem(target.NamingContainer);
string _tooltipText = (string)DataBinder.GetPropertyValue(dataItem, _propertyName);
if (!String.IsNullOrEmpty(_tooltipText))
{
Image image = new Image();
image.ImageUrl = _imageUrl;
image.ToolTip = _tooltipText;
target.Controls.Add(image);
}
}
}
En el primero (InitializeCell) lo que hacemos es comprobar que tipo de celda se está inicializando ya que tenemos 3 tipos posibles:
http://msdn.microsoft.com/en-us/library/yc8taz9h.aspx
y comprobamos que es del tipo DataControlCellType.DataCell (Las que tienen los controles y los datos) para suscribirmos a su evento DataBinding y ahí entra en juego el evento creado OnBindingField, en el que hacemos un cast del control que viene por parámetro a TableCell usando la palabra reservada as y sino no es nulo, obtenemos mediante el nombre de la propiedad que le añadimos al control el contenido de la propiedad del DataBinder, que en el caso de que no sea ni nula ni vacia, nos creamos un control imagen, al que le añadimos sus propiedades ImageUrl con la que tiene nuestro control y el ToolTip con el valor de la propiedad del DataBinder que hemos recogido.
Con esto hemos conseguido nuestro objetivo :)
Esto es todo!!!