Desarrollar controles de servidor web enlazados a datos personalizados para ASP.NET 2.0

Actualización: noviembre 2007

Un control de servidor Web enlazado a datos de ASP.NET proporciona una interfaz de usuario (IU) para un origen de datos que representa una colección de registros o elementos. Los controles de servidor Información general sobre GridView (Control de servidor Web), Información general sobre DataList (Control de servidor Web) y Información general sobre Repeater (Control de servidor Web) son ejemplos de controles de servidor Web enlazados a datos. Para obtener más información sobre los controles enlazados a datos incluidos con ASP.NET, vea Información general sobre los controles de servidor Web ASP.NET enlazados a datos.

En la versión 2.0 de ASP.NET, un nuevo modelo de origen de datos permite enlazar controles enlazados a datos a controles de código fuente, lo que permite sacar las operaciones de datos comunes (como paginación, ordenación y eliminación) del control enlazado a datos propiamente dicho. Este modelo da lugar a un control enlazado a datos más flexible para los desarrolladores de páginas y aumenta el nivel de reusabilidad.

En este tema se presentan los pasos básicos necesarios para implementar un control de servidor enlazado a datos personalizado de ASP.NET 2.0. Para obtener más información sobre la arquitectura y las implementaciones en general de los controles personalizados, vea Desarrollar controles de servidor ASP.NET personalizados y Tutorial: Desarrollar y utilizar un control de servidor personalizado. Para obtener más información sobre cómo desarrollar controles enlazados a datos compatibles con ASP.NET 1.1, vea Desarrollar controles de servidor Web enlazados a datos personalizados para ASP.NET 1.1 y Tutorial: Crear controles Web ASP.NET enlazados a datos personalizados para ASP.NET 1.1. Para obtener más información sobre los controles de origen de datos, vea Información general sobre los controles de origen de datos.

Cuándo crear un control enlazado a datos personalizado

Antes de crear un control enlazado a datos personalizado, revise las funciones de los controles enlazados a datos incluidos con ASP.NET. Los controles existentes podrían satisfacer sus necesidades, o bien, quizás opte por crear un control personalizado que amplíe un control existente que ya proporcione muchas de las características que necesita. Para obtener más información sobre los controles enlazados a datos proporcionados con ASP.NET, vea Información general sobre los controles de servidor Web ASP.NET enlazados a datos.

A continuación se citan algunos motivos por los que podría decidir crear un control enlazado a datos personalizado:

  • Sus necesidades concretas requieren una interfaz de usuario personalizada, características de ordenación o de edición de datos personalizadas que no están disponibles en los controles enlazados a datos existentes.

  • Desea crear un control enlazado a datos personalizado precompilado y redistribuible.

  • Desea ampliar las características de un control enlazado a datos proporcionado con ASP.NET.

  • Desea crear un control enlazado a datos con un diseñador personalizado que se ajuste a sus necesidades concretas.

Funcionalidad básica de un control enlazado a datos personalizado

Cuando se realiza una derivación de una de las clases base de controles enlazados a datos, como las clases DataBoundControl o CompositeDataBoundControl, el control enlazado a datos personalizado hereda automáticamente muchas características integradas, incluidas las siguientes:

  • Compatibilidad del origen de datos con la interfaz IDataSource y su clase DataSourceView relacionada, lo que proporciona vistas con nombre de los datos, la capacidad para consultar los tipos de operaciones admitidas por el almacén de datos y la funcionalidad de carga de datos a petición.

  • Compatibilidad del origen de datos con las interfaces genéricas IEnumerable o IListSource.

  • Compatibilidad con las expresiones de enlace de datos, lo que permite a los desarrolladores de páginas crear enlaces entre una propiedad expuesta especialmente marcada de un control y un origen de datos. Para obtener más información sobre las expresiones de enlace de datos, vea Información general sobre las expresiones de enlace de datos.

  • Compatibilidad con el enlace de datos automático que invoca la lógica de enlace de datos lo más tardío posible en el ciclo de vida de la página y sólo cuando es necesario, en lugar de hacerlo con cada devolución de datos. Después de que una página lleve a cabo la primera solicitud de enlace de datos, las solicitudes subsiguientes intentan recuperar los datos del estado de vista. De este modo se mejora el rendimiento ya que se evita la necesidad de volver a conectarse al origen de datos en cada solicitud.

Utilizar las características en tiempo de diseño disponibles

Hay características en tiempo de diseño disponibles para todos los controles de servidor Web que podrían considerarse para los controles enlazados a datos personalizados. Se puede crear una clase de diseñador y plantillas de control para el control personalizado. Estas características se invocan cuando se utiliza el control en tiempo de diseño en una superficie de diseño visual, como la vista Diseño de Visual Studio.

La creación de un diseñador de controles puede aumentar en gran medida la facilidad de uso de los controles personalizados en tiempo de diseño, puesto que proporciona una interfaz en tiempo de diseño que permite a los desarrolladores de páginas personalizar las propiedades de los controles. Para obtener información general sobre los diseñadores de controles ASP.NET, vea Información general sobre los diseñadores de controles ASP.NET. Para obtener ejemplos, vea HierarchicalDataBoundControlDesigner y Tutorial: Crear un diseñador de controles básico para un control de servidor Web.

Mediante la creación de un control con plantilla, los desarrolladores de páginas disponen de flexibilidad para especificar los controles y el marcado que definen la interfaz de usuario del control. Para obtener un ejemplo de un control con plantilla personalizado, vea Ejemplo de control de servidor con plantilla.

Implementar un control enlazado a datos personalizado en ASP.NET 2.0

En la tabla siguiente se resumen los pasos específicos de la implementación de un control de servidor enlazado a datos personalizado en ASP.NET 2.0. Debajo de la tabla hay información más detallada sobre cada uno de los pasos de implementación.

Paso

Resumen del paso

Elegir una clase base de controles enlazados a datos.

Extienda una clase de control enlazado a datos existente que ya proporciona muchas de las características que necesite, o bien, realice una derivación de una de las clases base de controles enlazados a datos.

Exponer las propiedades de enlace de datos.

Configure el control personalizado de modo que exponga las propiedades de enlace de datos adicionales a las mínimas necesarias expuestas por las clases base de controles enlazados a datos.

Iniciar la recuperación de datos.

  • Recupere los datos asignados al control por el desarrollador de páginas; para ello, siga este procedimiento:

  • Reemplace el método PerformSelect de la clase base de controles enlazados a datos.

  • Llame al método GetData de la clase base de controles enlazados a datos para recuperar la vista de origen de datos del control.

  • Llame al método Select del objeto DataSourceView para iniciar la recuperación de datos y especificar el método de devolución de llamada que recibirá los datos.

Controlar los datos recuperados.

Proporcione el método de devolución de llamada especificado como parámetro en el método Select. El método de devolución de llamada debe tener un parámetro único de tipo IEnumerable para poder recibir los datos. Si el control requiere algún tipo de procesamiento de los datos, dicho procesamiento deberá producirse dentro de este método de devolución de llamada.

Crear los objetos de la IU que representan los datos.

Proporcione un reemplazo del método PerformDataBinding. Debe ejecutar las tareas siguientes dentro de este método:

  • Llame al método PerformDataBinding para permitir la ejecución de cualquier otro código que se base en este método.

  • Enumere la recolección de datos y cree los controles secundarios que representen los datos en la visualización de la interfaz de usuario.

Elegir una clase base de controles enlazados a datos

Los desarrolladores de controles pueden extender una de las clases base de controles enlazados a datos disponibles para crear un control enlazado a datos personalizado. En la tabla siguiente figura una lista de las clases base enlazadas a datos disponibles en ASP.NET 2.0. Lea la descripción de cada clase base y, a continuación, determine cuál de ellas se ajusta más a los requisitos del control enlazado a datos personalizado. Para obtener información más detallada sobre cada clase base de controles enlazados a datos y ejemplos de implementación, consulte la documentación de referencia de cada clase. Para obtener más información sobre los controles enlazados a datos proporcionados por ASP.NET, vea Información general sobre los controles de servidor Web ASP.NET enlazados a datos.

Clase

Descripción

BaseDataBoundControl

  • Ésta es la clase base de todos los controles enlazados a datos, que lleva a cabo el enlace de datos y la validación de los datos enlazados.

DataBoundControl

Ésta es la clase base enlazada a datos que se utiliza para generar los controles enlazados a datos estándar. DataBoundControl se encarga de lo siguiente:

  • Proporciona la implementación básica compartida por todos los controles enlazados a datos.

  • Contiene la lógica necesaria para comunicarse con los controles de origen de datos y los contenedores de datos.

  • Sirve de base para los controles enlazados a datos, como TreeView y ListControl.

ListControl

  • Ésta es la clase base de los controles de lista y extiende la clase DataBoundControl. Proporciona una colección Items y funciones avanzadas de representación del diseño.

CompositeDataBoundControl

  • Ésta es la clase base que extiende la clase DataBoundControl y proporciona la funcionalidad siguiente:

  • Implementa el código típico que requieren los controles compuestos, incluido el código que restaura la jerarquía de controles secundarios del control a partir del estado de vista después de realizarse una devolución de datos.

  • Enlaza a un origen de datos IEnumerable y enumera los datos para generar un árbol de control.

  • Sirve de base para los controles enlazados a datos, como GridView y DetailsView.

HierarchicalDataBoundControl

  • Ésta es la clase base de los controles que muestran sus datos de manera jerárquica. Sirve de base para los controles enlazados a datos basados en un árbol, como TreeView y Menu.

Propiedades de enlace de datos proporcionadas

Las clases base de controles enlazados a datos proporcionan ya las propiedades de enlace de datos expuestas necesarias para que un desarrollador de páginas pueda enlazar un origen de datos a un control. El autor del control no necesita realizar ningún trabajo adicional. Por ejemplo, al realizar una derivación de DataBoundControl, un control personalizado hereda tres propiedades de enlace de datos expuestas: DataSourceID, DataSource y DataMember. A continuación, el desarrollador de páginas puede especificar el origen de datos al que se enlazará el control estableciendo el valor de la propiedad DataSource o de la propiedad DataSourceID.

La propiedad DataSourceID permite al desarrollador de páginas especificar el Id. de un control que representa el origen de datos del que el control enlazado a datos recupera sus datos.

La propiedad DataSource permite al desarrollador de páginas enlazar un control enlazado a datos directamente a estos dos tipos de objetos de datos:

  • Un objeto que implemente la interfaz IEnumerable, como un objeto Array, ArrayList o Hashtable.

  • Un objeto que implemente la interfaz IListSource, como un objeto DataSet.

  • Las propiedades de enlace de datos adicionales, como DataMember, permiten al desarrollador de páginas especificar la parte de la recolección de datos a la que debe enlazarse el control.

  • Para obtener más información sobre las propiedades de enlace de datos expuestas proporcionadas por cada clase de controles enlazados a datos o clase base enlazada a datos, consulte la documentación de referencia correspondiente a cada clase.

Exponer propiedades de enlace de datos personalizadas

Cuando se exponen propiedades de enlace de datos personalizadas en un control personalizado o se reemplazan propiedades de enlace de datos existentes, se debe llamar al método OnDataPropertyChanged si ya se ha inicializado el control. De este modo, se obliga al control enlazado a datos a volver a enlazar los datos para que pueda utilizar el nuevo valor de la propiedad de enlace de datos.

En el ejemplo de código siguiente se muestra una propiedad que pertenece a una clase de control enlazado a datos derivada. En el ejemplo se muestra cómo un control enlazado a datos puede llamar al método OnDataPropertyChanged si se cambia una propiedad que identifica un origen de datos una vez inicializado el control enlazado a datos.

Inherits DataBoundControl

Public Property DataTextField() As String
    Get
        Dim o As Object = ViewState("DataTextField")
        If o Is Nothing Then
            Return String.Empty
        Else
            Return CStr(o)
        End If
    End Get
    Set(ByVal value As String)
        ViewState("DataTextField") = value
        If (Initialized) Then
            OnDataPropertyChanged()
        End If
    End Set
End Property
public class SimpleDataBoundColumn : DataBoundControl
{
    public string DataTextField
    {
        get
        {
            object o = ViewState["DataTextField"];
            return ((o == null) ? string.Empty : (string)o);
        }
        set
        {
            ViewState["DataTextField"] = value;
            if (Initialized)
            {
                OnDataPropertyChanged();
            }
        }
    }

Iniciar la recuperación de datos

La recuperación de datos se inicia dentro de un reemplazo del método PerformSelect heredado por el control base enlazado a datos del control. Dentro del reemplazo, se realiza una llamada para recuperar los datos y especificar un método de devolución de llamada que controlará los datos una vez devueltos.

Para recuperar datos, realice las tareas siguientes en el método PerformSelect reemplazado:

  1. Determine si el desarrollador de páginas utilizó la propiedad DataSource o la propiedad DataSourceID para establecer los datos que se van a enlazar al control. Para ello, compruebe la propiedad IsBoundUsingDataSourceID. Por ejemplo, el valor false de la propiedad IsBoundUsingDataSourceID indica que se utilizó la propiedad DataSource para especificar el origen de datos.

  2. Si el desarrollador de páginas estableció el valor de la propiedad DataSource, se requiere un paso adicional: llamar al método OnDataBinding.

  3. Llame al método GetData para recuperar el objeto DataSourceView asociado al control enlazado a datos.

  4. Llame al método Select del objeto DataSourceView recuperado para iniciar la recuperación de datos y especificar el método de devolución de llamada que controlará los datos recuperados. El método Select funciona de manera asincrónica, por lo que se permiten otros procesos mientras se recuperan los datos.

  5. Indique la finalización de las tareas PerformSelect estableciendo el valor de la propiedad RequiresDataBinding en false y llamando al método MarkAsDataBound.

  6. Produce el evento OnDataBound.

En el ejemplo de código siguiente, se muestran las tareas de recuperación de datos anteriormente descritas que se llevan a cabo dentro de un reemplazo del método PerformSelect.

Protected Overrides Sub PerformSelect()
    ' Call OnDataBinding here if bound to a data source using the
    ' DataSource property (instead of a DataSourceID), because the
    ' databinding statement is evaluated before the call to GetData.       
    If Not IsBoundUsingDataSourceID Then
        OnDataBinding(EventArgs.Empty)
    End If

    ' The GetData method retrieves the DataSourceView object from  
    ' the IDataSource associated with the data-bound control.            
    GetData().Select(CreateDataSourceSelectArguments(), _
        AddressOf OnDataSourceViewSelectCallback)

    ' The PerformDataBinding method has completed.
    RequiresDataBinding = False
    MarkAsDataBound()

    ' Raise the DataBound event.
    OnDataBound(EventArgs.Empty)

End Sub
protected override void PerformSelect()
{
    // Call OnDataBinding here if bound to a data source using the
    // DataSource property (instead of a DataSourceID), because the
    // databinding statement is evaluated before the call to GetData.       
    if (!IsBoundUsingDataSourceID)
    {
        this.OnDataBinding(EventArgs.Empty);
    }

    // The GetData method retrieves the DataSourceView object from  
    // the IDataSource associated with the data-bound control.            
    GetData().Select(CreateDataSourceSelectArguments(),
        this.OnDataSourceViewSelectCallback);

    // The PerformDataBinding method has completed.
    RequiresDataBinding = false;
    MarkAsDataBound();

    // Raise the DataBound event.
    OnDataBound(EventArgs.Empty);
}

Controlar los datos recuperados

Cree su propio método de devolución de llamada para aceptar los datos recuperados. Se trata del método de devolución de llamada que especificó al llamar al método Select dentro del reemplazo del método PerformSelect. El método de devolución de llamada sólo puede contener un parámetro de tipo IEnumerable. En el método de devolución de llamada se puede realizar cualquier procesamiento de los datos devueltos si así lo requiere el control. Por último, llame al método PerformDataBinding.

En el ejemplo de código siguiente se muestra un método de devolución de llamada que tiene un parámetro de tipo IEnumerable y llama al método PerformDataBinding.

Private Sub OnDataSourceViewSelectCallback(ByVal retrievedData As IEnumerable)
    ' Call OnDataBinding only if it has not already been 
    ' called in the PerformSelect method.
    If IsBoundUsingDataSourceID Then
        OnDataBinding(EventArgs.Empty)
    End If
    ' The PerformDataBinding method binds the data in the  
    ' retrievedData collection to elements of the data-bound control.
    PerformDataBinding(retrievedData)

End Sub
private void OnDataSourceViewSelectCallback(IEnumerable retrievedData)
{
    // Call OnDataBinding only if it has not already been 
    // called in the PerformSelect method.
    if (IsBoundUsingDataSourceID)
    {
        OnDataBinding(EventArgs.Empty);
    }
    // The PerformDataBinding method binds the data in the  
    // retrievedData collection to elements of the data-bound control.
    PerformDataBinding(retrievedData);
}

Crear los objetos de la IU que representan los datos

Dentro de un reemplazo del método PerformDataBinding, se crean los controles secundarios que representarán los datos. Se enumera la recolección de datos, se crean los controles secundarios y se establecen sus propiedades basándose en cada elemento de datos. La adición de los nuevos controles secundarios a la colección Controls del control permite representar los controles secundarios. La jerarquía de los controles se representa durante el método Render heredado del control. Si lo desea, puede reemplazar el método Render para realizar la representación especial requerida por el control personalizado, como incluir elementos HTML adicionales o una representación especial para mostrarlo en modo de diseño.

Para crear los objetos de la IU que representen los datos, reemplace el método PerformDataBinding y lleve a cabo las tareas siguientes:

  1. Llame al método PerformDataBinding para permitir la ejecución de cualquier otro código que se base en este método.

  2. Enumere la recolección de datos y cree los controles secundarios que representen los datos en la visualización de la interfaz de usuario. Agregue cada control secundario a la colección del control llamando al método Add del control.

  • En el siguiente ejemplo de código se muestra cómo reemplazar el método PerformDataBinding. Se llama al método PerformDataBinding para permitir la ejecución de cualquier otro código que se base en este método. Se enumera la recolección de datos y se crean los controles secundarios para representar los datos en la visualización de la interfaz de usuario.
        Protected Overrides Sub PerformDataBinding(ByVal retrievedData As IEnumerable)
            MyBase.PerformDataBinding(retrievedData)

            ' Verify data exists.
            If Not (retrievedData Is Nothing) Then
                Dim tbl As New Table()
                Dim row As TableRow
                Dim cell As TableCell
                Dim dataStr As String = String.Empty

                Dim dataItem As Object
                For Each dataItem In retrievedData
                    ' If the DataTextField was specified get the data
                    ' from that field, otherwise get the data from the first field. 
                    If DataTextField.Length > 0 Then
                        dataStr = DataBinder.GetPropertyValue(dataItem, DataTextField, Nothing)
                    Else
                        Dim props As PropertyDescriptorCollection = TypeDescriptor.GetProperties(dataItem)
                        If props.Count >= 1 Then
                            If Nothing <> props(0).GetValue(dataItem) Then
                                dataStr = props(0).GetValue(dataItem).ToString()
                            End If
                        End If
                    End If

                    row = New TableRow()
                    tbl.Rows.Add(row)
                    cell = New TableCell()
                    cell.Text = dataStr
                    row.Cells.Add(cell)
                Next dataItem

                Controls.Add(tbl)
            End If

        End Sub
    End Class
End Namespace
protected override void PerformDataBinding(IEnumerable retrievedData)
{
    base.PerformDataBinding(retrievedData);

    // Verify data exists.
    if (retrievedData != null)
    {
        Table tbl = new Table();
        TableRow row;
        TableCell cell;
        string dataStr = String.Empty;

        foreach (object dataItem in retrievedData)
        {
            // If the DataTextField was specified get the data
            // from that field, otherwise get the data from the first field. 
            if (DataTextField.Length > 0)
            {
                dataStr = DataBinder.GetPropertyValue(dataItem,
                    DataTextField, null);
            }
            else
            {
                PropertyDescriptorCollection props =
                        TypeDescriptor.GetProperties(dataItem);
                if (props.Count >= 1)
                {
                    if (null != props[0].GetValue(dataItem))
                    {
                        dataStr = props[0].GetValue(dataItem).ToString();
                    }
                }
            }

            row = new TableRow();
            tbl.Rows.Add(row);
            cell = new TableCell();
            cell.Text = dataStr;
            row.Cells.Add(cell);
        }

        this.Controls.Add(tbl); 
    }
}

Generar un control de servidor personalizado

Para obtener información sobre cómo generar un control de servidor Web enlazado a datos personalizado y utilizarlo en una página Web, vea Generar ejemplos de controles de servidor personalizados.

Vea también

Tareas

Tutorial: Crear controles Web ASP.NET enlazados a datos personalizados para ASP.NET 2.0

Tutorial: Desarrollar y utilizar un control de servidor personalizado

Conceptos

Información general sobre los controles de servidor Web ASP.NET enlazados a datos

Atributos de metadatos para controles de servidor personalizados

Información general sobre los diseñadores de controles ASP.NET

Referencia

HierarchicalDataBoundControlDesigner

Otros recursos

Desarrollar controles de servidor ASP.NET personalizados