Ejemplo de control enlazado a datos a partir de plantillas
El control TemplatedList
descrito en el ejemplo siguiente es una versión simplificada del control System.Web.UI.DataList. En él se ilustran los conceptos siguientes:
Enlace a datos, como se describe en Desarrollar un control enlazado a datos a partir de plantillas.
DataSource
es el origen de datos deTemplatedList
.ItemTemplate
es la propiedad de plantilla deTemplatedList
.TemplatedListItem
es el contenedor lógico deItemTemplate.TemplatedListItem
tiene una propiedad,DataItem
, que enlaza cada elemento deDataSource
.Ejecución de eventos, como se describe en Ejecutar un evento.
TemplatedListItem
ejecuta los eventos de comando a partir de los controles de la plantilla enTemplatedList. TemplatedList
expone los eventos ejecutados como eventosItemCommand
. La claseTemplatedListCommandEventArgs
contiene los datos del evento.Exposición de los estilos de un control, como se describe en Estilos de los controles de servidor.
TemplatedList
expone las propiedadesItemStyle
,AlternatingItemStyle
ySelectedItemStyle
de System.Web.UI.WebControls.TableStyle.Personalización de la restauración del estado con ViewState.
TemplatedList
reemplaza los métodos SaveViewState y LoadViewState heredados de Control para personalizar la restauración de sus propiedades Style.Aplicación de atributos de metadatos en tiempo de diseño. Para obtener más información acerca de los atributos en tiempo de diseño, vea Atributos y compatibilidad en tiempo de diseño. El diseñador (
CustomControls.Design.TemplatedListDesigner
) especificado en DesignerAttribute se implementa en Ejemplo de diseñador de controles de formularios Web Forms enlazados a datos a partir de plantillas.
Para generar el ejemplo, vea las instrucciones en Ejemplos de control de servidor.
// TemplatedList.cs.
namespace CustomControls {
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Collections;
using System.Diagnostics;
using System.Web.UI;
using System.Web.UI.WebControls;
[
DefaultEvent("SelectedIndexChanged"),
DefaultProperty("DataSource"),
Designer("CustomControls.Design.TemplatedListDesigner, CustomControls.Design", typeof(IDesigner))
]
public class TemplatedList : WebControl, INamingContainer {
#region Statics and Constants
private static readonly object EventSelectedIndexChanged = new object();
private static readonly object EventItemCreated = new object();
private static readonly object EventItemDataBound = new object();
private static readonly object EventItemCommand = new object();
#endregion
#region Member variables
private IEnumerable dataSource;
private TableItemStyle itemStyle;
private TableItemStyle alternatingItemStyle;
private TableItemStyle selectedItemStyle;
private ITemplate itemTemplate;
#endregion
#region Properties
[
Category("Style"),
Description("The style to be applied to alternate items."),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
NotifyParentProperty(true),
PersistenceMode(PersistenceMode.InnerProperty),
]
public virtual TableItemStyle AlternatingItemStyle {
get {
if (alternatingItemStyle == null) {
alternatingItemStyle = new TableItemStyle();
if (IsTrackingViewState)
((IStateManager)alternatingItemStyle).TrackViewState();
}
return alternatingItemStyle;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(-1),
Description("The cell padding of the rendered table.")
]
public virtual int CellPadding {
get {
if (ControlStyleCreated == false) {
return -1;
}
return ((TableStyle)ControlStyle).CellPadding;
}
set {
((TableStyle)ControlStyle).CellPadding = value;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(0),
Description("The cell spacing of the rendered table.")
]
public virtual int CellSpacing {
get {
if (ControlStyleCreated == false) {
return 0;
}
return ((TableStyle)ControlStyle).CellSpacing;
}
set {
((TableStyle)ControlStyle).CellSpacing = value;
}
}
[
Bindable(true),
Category("Data"),
DefaultValue(null),
Description("The data source used to build up the control."),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public IEnumerable DataSource {
get {
return dataSource;
}
set {
dataSource = value;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(GridLines.None),
Description("The grid lines to be shown in the rendered table.")
]
public virtual GridLines GridLines {
get {
if (ControlStyleCreated == false) {
return GridLines.None;
}
return ((TableStyle)ControlStyle).GridLines;
}
set {
((TableStyle)ControlStyle).GridLines = value;
}
}
[
Category("Style"),
Description("The style to be applied to all items."),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
NotifyParentProperty(true),
PersistenceMode(PersistenceMode.InnerProperty),
]
public virtual TableItemStyle ItemStyle {
get {
if (itemStyle == null) {
itemStyle = new TableItemStyle();
if (IsTrackingViewState)
((IStateManager)itemStyle).TrackViewState();
}
return itemStyle;
}
}
[
Browsable(false),
DefaultValue(null),
Description("The content to be shown in each item."),
PersistenceMode(PersistenceMode.InnerProperty),
TemplateContainer(typeof(TemplatedListItem))
]
public virtual ITemplate ItemTemplate {
get {
return itemTemplate;
}
set {
itemTemplate = value;
}
}
[
Bindable(true),
DefaultValue(-1),
Description("The index of the selected item.")
]
public virtual int SelectedIndex {
get {
object o = ViewState["SelectedIndex"];
if (o != null)
return(int)o;
return -1;
}
set {
if (value < -1) {
throw new ArgumentOutOfRangeException();
}
int oldSelectedIndex = SelectedIndex;
ViewState["SelectedIndex"] = value;
if (HasControls()) {
Table table = (Table)Controls[0];
TemplatedListItem item;
if ((oldSelectedIndex != -1) && (table.Rows.Count > oldSelectedIndex)) {
item = (TemplatedListItem)table.Rows[oldSelectedIndex];
if (item.ItemType != ListItemType.EditItem) {
ListItemType itemType = ListItemType.Item;
if (oldSelectedIndex % 2 != 0)
itemType = ListItemType.AlternatingItem;
item.SetItemType(itemType);
}
}
if ((value != -1) && (table.Rows.Count > value)) {
item = (TemplatedListItem)table.Rows[value];
item.SetItemType(ListItemType.SelectedItem);
}
}
}
}
[
Category("Style"),
Description("The style to be applied to the selected item."),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
NotifyParentProperty(true),
PersistenceMode(PersistenceMode.InnerProperty),
]
public virtual TableItemStyle SelectedItemStyle {
get {
if (selectedItemStyle == null) {
selectedItemStyle = new TableItemStyle();
if (IsTrackingViewState)
((IStateManager)selectedItemStyle).TrackViewState();
}
return selectedItemStyle;
}
}
#endregion
#region Events
protected virtual void OnItemCommand(TemplatedListCommandEventArgs e) {
TemplatedListCommandEventHandler onItemCommandHandler = (TemplatedListCommandEventHandler)Events[EventItemCommand];
if (onItemCommandHandler != null) onItemCommandHandler(this, e);
}
protected virtual void OnItemCreated(TemplatedListItemEventArgs e) {
TemplatedListItemEventHandler onItemCreatedHandler = (TemplatedListItemEventHandler)Events[EventItemCreated];
if (onItemCreatedHandler != null) onItemCreatedHandler(this, e);
}
protected virtual void OnItemDataBound(TemplatedListItemEventArgs e) {
TemplatedListItemEventHandler onItemDataBoundHandler = (TemplatedListItemEventHandler)Events[EventItemDataBound];
if (onItemDataBoundHandler != null) onItemDataBoundHandler(this, e);
}
protected virtual void OnSelectedIndexChanged(EventArgs e) {
EventHandler handler = (EventHandler)Events[EventSelectedIndexChanged];
if (handler != null) handler(this, e);
}
[
Category("Action"),
Description("Raised when a CommandEvent occurs within an item.")
]
public event TemplatedListCommandEventHandler ItemCommand {
add {
Events.AddHandler(EventItemCommand, value);
}
remove {
Events.RemoveHandler(EventItemCommand, value);
}
}
[
Category("Behavior"),
Description("Raised when an item is created and is ready for customization.")
]
public event TemplatedListItemEventHandler ItemCreated {
add {
Events.AddHandler(EventItemCreated, value);
}
remove {
Events.RemoveHandler(EventItemCreated, value);
}
}
[
Category("Behavior"),
Description("Raised when an item is data-bound.")
]
public event TemplatedListItemEventHandler ItemDataBound {
add {
Events.AddHandler(EventItemDataBound, value);
}
remove {
Events.RemoveHandler(EventItemDataBound, value);
}
}
[
Category("Action"),
Description("Raised when the SelectedIndex property has changed.")
]
public event EventHandler SelectedIndexChanged {
add {
Events.AddHandler(EventSelectedIndexChanged, value);
}
remove {
Events.RemoveHandler(EventSelectedIndexChanged, value);
}
}
#endregion
#region Methods and Implementation
protected override void CreateChildControls() {
Controls.Clear();
if (ViewState["ItemCount"] != null) {
// Create the control hierarchy using the view state,
// not the data source.
CreateControlHierarchy(false);
}
}
private void CreateControlHierarchy(bool useDataSource) {
IEnumerable dataSource = null;
int count = -1;
if (useDataSource == false) {
// ViewState must have a non-null value for ItemCount because this is checked
// by CreateChildControls.
count = (int)ViewState["ItemCount"];
if (count != -1) {
dataSource = new DummyDataSource(count);
}
}
else {
dataSource = this.dataSource;
}
if (dataSource != null) {
Table table = new Table();
Controls.Add(table);
int selectedItemIndex = SelectedIndex;
int index = 0;
count = 0;
foreach (object dataItem in dataSource) {
ListItemType itemType = ListItemType.Item;
if (index == selectedItemIndex) {
itemType = ListItemType.SelectedItem;
}
else if (index % 2 != 0) {
itemType = ListItemType.AlternatingItem;
}
CreateItem(table, index, itemType, useDataSource, dataItem);
count++;
index++;
}
}
if (useDataSource) {
// Save the number of items contained for use in round trips.
ViewState["ItemCount"] = ((dataSource != null) ? count : -1);
}
}
protected override Style CreateControlStyle() {
// Since the TemplatedList control renders an HTML table,
// an instance of the TableStyle class is used as the control style.
TableStyle style = new TableStyle(ViewState);
// Set up default initial state.
style.CellSpacing = 0;
return style;
}
private TemplatedListItem CreateItem(Table table, int itemIndex, ListItemType itemType, bool dataBind, object dataItem) {
TemplatedListItem item = new TemplatedListItem(itemIndex, itemType);
TemplatedListItemEventArgs e = new TemplatedListItemEventArgs(item);
if (itemTemplate != null) {
itemTemplate.InstantiateIn(item.Cells[0]);
}
if (dataBind) {
item.DataItem = dataItem;
}
OnItemCreated(e);
table.Rows.Add(item);
if (dataBind) {
item.DataBind();
OnItemDataBound(e);
item.DataItem = null;
}
return item;
}
public override void DataBind() {
// Controls with a data-source property perform their custom data binding
// by overriding DataBind.
// Evaluate any data-binding expressions on the control itself.
base.OnDataBinding(EventArgs.Empty);
// Reset the control state.
Controls.Clear();
ClearChildViewState();
// Create the control hierarchy using the data source.
CreateControlHierarchy(true);
ChildControlsCreated = true;
TrackViewState();
}
protected override void LoadViewState(object savedState) {
// Customize state management to handle saving state of contained objects.
if (savedState != null) {
object[] myState = (object[])savedState;
if (myState[0] != null)
base.LoadViewState(myState[0]);
if (myState[1] != null)
((IStateManager)ItemStyle).LoadViewState(myState[1]);
if (myState[2] != null)
((IStateManager)SelectedItemStyle).LoadViewState(myState[2]);
if (myState[3] != null)
((IStateManager)AlternatingItemStyle).LoadViewState(myState[3]);
}
}
protected override bool OnBubbleEvent(object source, EventArgs e) {
// Handle events raised by children by overriding OnBubbleEvent.
bool handled = false;
if (e is TemplatedListCommandEventArgs) {
TemplatedListCommandEventArgs ce = (TemplatedListCommandEventArgs)e;
OnItemCommand(ce);
handled = true;
if (String.Compare(ce.CommandName, "Select", true) == 0) {
SelectedIndex = ce.Item.ItemIndex;
OnSelectedIndexChanged(EventArgs.Empty);
}
}
return handled;
}
private void PrepareControlHierarchy() {
if (HasControls() == false) {
return;
}
Debug.Assert(Controls[0] is Table);
Table table = (Table)Controls[0];
table.CopyBaseAttributes(this);
if (ControlStyleCreated) {
table.ApplyStyle(ControlStyle);
}
// The composite alternating item style; do just one
// merge style on the actual item.
Style altItemStyle = null;
if (alternatingItemStyle != null) {
altItemStyle = new TableItemStyle();
altItemStyle.CopyFrom(itemStyle);
altItemStyle.CopyFrom(alternatingItemStyle);
}
else {
altItemStyle = itemStyle;
}
int rowCount = table.Rows.Count;
for (int i = 0; i < rowCount; i++) {
TemplatedListItem item = (TemplatedListItem)table.Rows[i];
Style compositeStyle = null;
switch (item.ItemType) {
case ListItemType.Item:
compositeStyle = itemStyle;
break;
case ListItemType.AlternatingItem:
compositeStyle = altItemStyle;
break;
case ListItemType.SelectedItem: {
compositeStyle = new TableItemStyle();
if (item.ItemIndex % 2 != 0)
compositeStyle.CopyFrom(altItemStyle);
else
compositeStyle.CopyFrom(itemStyle);
compositeStyle.CopyFrom(selectedItemStyle);
}
break;
}
if (compositeStyle != null) {
item.MergeStyle(compositeStyle);
}
}
}
protected override void Render(HtmlTextWriter writer) {
// Apply styles to the control hierarchy
// and then render it out.
// Apply styles during render phase, so the user can change styles
// after calling DataBind without the property changes ending
// up in view state.
PrepareControlHierarchy();
RenderContents(writer);
}
protected override object SaveViewState() {
// Customized state management to handle saving state of contained objects such as styles.
object baseState = base.SaveViewState();
object itemStyleState = (itemStyle != null) ? ((IStateManager)itemStyle).SaveViewState() : null;
object selectedItemStyleState = (selectedItemStyle != null) ? ((IStateManager)selectedItemStyle).SaveViewState() : null;
object alternatingItemStyleState = (alternatingItemStyle != null) ? ((IStateManager)alternatingItemStyle).SaveViewState() : null;
object[] myState = new object[4];
myState[0] = baseState;
myState[1] = itemStyleState;
myState[2] = selectedItemStyleState;
myState[3] = alternatingItemStyleState;
return myState;
}
protected override void TrackViewState() {
// Customized state management to handle saving state of contained objects such as styles.
base.TrackViewState();
if (itemStyle != null)
((IStateManager)itemStyle).TrackViewState();
if (selectedItemStyle != null)
((IStateManager)selectedItemStyle).TrackViewState();
if (alternatingItemStyle != null)
((IStateManager)alternatingItemStyle).TrackViewState();
}
#endregion
}
public class TemplatedListItem : TableRow, INamingContainer {
private int itemIndex;
private ListItemType itemType;
private object dataItem;
public TemplatedListItem(int itemIndex, ListItemType itemType) {
this.itemIndex = itemIndex;
this.itemType = itemType;
Cells.Add(new TableCell());
}
public virtual object DataItem {
get {
return dataItem;
}
set {
dataItem = value;
}
}
public virtual int ItemIndex {
get {
return itemIndex;
}
}
public virtual ListItemType ItemType {
get {
return itemType;
}
}
protected override bool OnBubbleEvent(object source, EventArgs e) {
if (e is CommandEventArgs) {
// Add the information about Item to CommandEvent.
TemplatedListCommandEventArgs args =
new TemplatedListCommandEventArgs(this, source, (CommandEventArgs)e);
RaiseBubbleEvent(this, args);
return true;
}
return false;
}
internal void SetItemType(ListItemType itemType) {
this.itemType = itemType;
}
}
public sealed class TemplatedListCommandEventArgs : CommandEventArgs {
private TemplatedListItem item;
private object commandSource;
public TemplatedListCommandEventArgs(TemplatedListItem item, object commandSource, CommandEventArgs originalArgs) :
base(originalArgs) {
this.item = item;
this.commandSource = commandSource;
}
public TemplatedListItem Item {
get {
return item;
}
}
public object CommandSource {
get {
return commandSource;
}
}
}
public delegate void TemplatedListCommandEventHandler(object source, TemplatedListCommandEventArgs e);
public sealed class TemplatedListItemEventArgs : EventArgs {
private TemplatedListItem item;
public TemplatedListItemEventArgs(TemplatedListItem item) {
this.item = item;
}
public TemplatedListItem Item {
get {
return item;
}
}
}
public delegate void TemplatedListItemEventHandler(object sender, TemplatedListItemEventArgs e);
internal sealed class DummyDataSource : ICollection {
private int dataItemCount;
public DummyDataSource(int dataItemCount) {
this.dataItemCount = dataItemCount;
}
public int Count {
get {
return dataItemCount;
}
}
public bool IsReadOnly {
get {
return false;
}
}
public bool IsSynchronized {
get {
return false;
}
}
public object SyncRoot {
get {
return this;
}
}
public void CopyTo(Array array, int index) {
for (IEnumerator e = this.GetEnumerator(); e.MoveNext();)
array.SetValue(e.Current, index++);
}
public IEnumerator GetEnumerator() {
return new DummyDataSourceEnumerator(dataItemCount);
}
private class DummyDataSourceEnumerator : IEnumerator {
private int count;
private int index;
public DummyDataSourceEnumerator(int count) {
this.count = count;
this.index = -1;
}
public object Current {
get {
return null;
}
}
public bool MoveNext() {
index++;
return index < count;
}
public void Reset() {
this.index = -1;
}
}
}
}
[Visual Basic]
' TemplatedList.vb
Imports System
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.ComponentModel.Design.Serialization
Imports System.Collections
Imports System.Diagnostics
Imports System.Web.UI
Imports System.Web.UI.WebControls
Namespace CustomControls
<DefaultEvent("SelectedIndexChanged"), _
DefaultProperty("DataSource"), _
Designer("CustomControls.Design.TemplatedListDesigner, CustomControls.Design", _
GetType(IDesigner))> _
Public Class TemplatedList
Inherits WebControl
Implements INamingContainer
#Region "Statics and Constants"
Private Shared EventSelectedIndexChanged As New Object()
Private Shared EventItemCreated As New Object()
Private Shared EventItemDataBound As New Object()
Private Shared EventItemCommand As New Object()
#End Region
#Region "Member variables"
Private _dataSource As IEnumerable
Private _itemStyle As TableItemStyle '
Private _alternatingItemStyle As TableItemStyle
Private _selectedItemStyle As TableItemStyle
Private _itemTemplate As ITemplate
#End Region
#Region "Properties"
<Category("Style"), _
Description("The style to be applied to alternate items."), _
DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _
NotifyParentProperty(True), _
PersistenceMode(PersistenceMode.InnerProperty)> _
Public Overridable ReadOnly Property AlternatingItemStyle() As TableItemStyle
Get
If _alternatingItemStyle Is Nothing Then
_alternatingItemStyle = New TableItemStyle()
If IsTrackingViewState Then
CType(_alternatingItemStyle, IStateManager).TrackViewState()
End If
End If
Return _alternatingItemStyle
End Get
End Property
<Bindable(True), _
Category("Appearance"), _
DefaultValue(- 1), _
Description("The cell padding of the rendered table.")> _
Public Overridable Property CellPadding() As Integer
Get
If ControlStyleCreated = False Then
Return - 1
End If
Return CType(ControlStyle, TableStyle).CellPadding
End Get
Set
CType(ControlStyle, TableStyle).CellPadding = value
End Set
End Property
<Bindable(True), _
Category("Appearance"), _
DefaultValue(0), _
Description("The cell spacing of the rendered table.")> _
Public Overridable Property CellSpacing() As Integer
Get
If ControlStyleCreated = False Then
Return 0
End If
Return CType(ControlStyle, TableStyle).CellSpacing
End Get
Set
CType(ControlStyle, TableStyle).CellSpacing = value
End Set
End Property
<Bindable(True), _
Category("Data"), _
Description("The data source used to build up the control."), _
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
Public Property DataSource() As IEnumerable
Get
Return _dataSource
End Get
Set
_dataSource = value
End Set
End Property
<Bindable(True), _
Category("Appearance"), _
DefaultValue(System.Web.UI.WebControls.GridLines.None), _
Description("The grid lines to be shown in the rendered table.")> _
Public Overridable Property GridLines() As GridLines
Get
If ControlStyleCreated = False Then
Return GridLines.None
End If
Return CType(ControlStyle, TableStyle).GridLines
End Get
Set
CType(ControlStyle, TableStyle).GridLines = value
End Set
End Property
<Category("Style"), _
Description("The style to be applied to all items."), _
DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _
NotifyParentProperty(True), _
PersistenceMode(PersistenceMode.InnerProperty)> _
Public Overridable ReadOnly Property ItemStyle() As TableItemStyle
Get
If _itemStyle Is Nothing Then
_itemStyle = New TableItemStyle()
If IsTrackingViewState Then
CType(_itemStyle, IStateManager).TrackViewState()
End If
End If
Return _itemStyle
End Get
End Property
<Browsable(False), _
Description("The content to be shown in each item."), _
PersistenceMode(PersistenceMode.InnerProperty), _
TemplateContainer(GetType(TemplatedListItem))> _
Public Overridable Property ItemTemplate() As ITemplate
Get
Return _itemTemplate
End Get
Set
_itemTemplate = value
End Set
End Property
<Bindable(True), _
DefaultValue(- 1), _
Description("The index of the selected item.")> _
Public Overridable Property SelectedIndex() As Integer
Get
Dim o As Object = ViewState("SelectedIndex")
If Not (o Is Nothing) Then
Return CInt(o)
End If
Return - 1
End Get
Set
If value < - 1 Then
Throw New ArgumentOutOfRangeException()
End If
Dim oldSelectedIndex As Integer = SelectedIndex
ViewState("SelectedIndex") = value
If HasControls() Then
Dim table As Table = CType(Controls(0), Table)
Dim item As TemplatedListItem
If oldSelectedIndex <> - 1 And table.Rows.Count > oldSelectedIndex Then
item = CType(table.Rows(oldSelectedIndex), TemplatedListItem)
If item.ItemType <> ListItemType.EditItem Then
Dim itemType As ListItemType = ListItemType.Item
If oldSelectedIndex Mod 2 <> 0 Then
itemType = ListItemType.AlternatingItem
End If
item.SetItemType(itemType)
End If
End If
If value <> - 1 And table.Rows.Count > value Then
item = CType(table.Rows(value), TemplatedListItem)
item.SetItemType(ListItemType.SelectedItem)
End If
End If
End Set
End Property
<Category("Style"), _
Description("The style to be applied to the selected item."), _
DesignerSerializationVisibility( _
DesignerSerializationVisibility.Content), _
NotifyParentProperty(True), _
PersistenceMode(PersistenceMode.InnerProperty)> _
Public Overridable ReadOnly Property SelectedItemStyle() As TableItemStyle
Get
If _selectedItemStyle Is Nothing Then
_selectedItemStyle = New TableItemStyle()
If IsTrackingViewState Then
CType(_selectedItemStyle, IStateManager).TrackViewState()
End If
End If
Return _selectedItemStyle
End Get
End Property
#End Region
#Region "Events"
Protected Overridable Sub OnItemCommand(e As TemplatedListCommandEventArgs)
Dim onItemCommandHandler As TemplatedListCommandEventHandler = CType(Events(EventItemCommand), TemplatedListCommandEventHandler)
If Not (onItemCommandHandler Is Nothing) Then
onItemCommandHandler(Me, e)
End If
End Sub
Protected Overridable Sub OnItemCreated(e As TemplatedListItemEventArgs)
Dim onItemCreatedHandler As TemplatedListItemEventHandler = CType(Events(EventItemCreated), TemplatedListItemEventHandler)
If Not (onItemCreatedHandler Is Nothing) Then
onItemCreatedHandler(Me, e)
End If
End Sub
Protected Overridable Sub OnItemDataBound(e As TemplatedListItemEventArgs)
Dim onItemDataBoundHandler As TemplatedListItemEventHandler = CType(Events(EventItemDataBound), TemplatedListItemEventHandler)
If Not (onItemDataBoundHandler Is Nothing) Then
onItemDataBoundHandler(Me, e)
End If
End Sub
Protected Overridable Sub OnSelectedIndexChanged(e As EventArgs)
Dim handler As EventHandler = CType(Events(EventSelectedIndexChanged), EventHandler)
If Not (handler Is Nothing) Then
handler(Me, e)
End If
End Sub
<Category("Action"), _
Description("Raised when a CommandEvent occurs within an item.")> _
Public Event ItemCommand As TemplatedListCommandEventHandler
<Category("Behavior"), _
Description("Raised when an item is created and is ready for customization.")> _
Public Event ItemCreated As TemplatedListItemEventHandler
<Category("Behavior"), _
Description("Raised when an item is data-bound.")> _
Public Event ItemDataBound As TemplatedListItemEventHandler
<Category("Action"), _
Description("Raised when the SelectedIndex property has changed.")> _
Public Event SelectedIndexChanged As EventHandler
#End Region
#Region "Methods and Implementation"
Protected Overrides Sub CreateChildControls()
Controls.Clear()
If Not (ViewState("ItemCount") Is Nothing) Then
' Create the control hierarchy using the view state,
' not the data source.
CreateControlHierarchy(False)
End If
End Sub
Private Sub CreateControlHierarchy(useDataSource As Boolean)
Dim dataSource As IEnumerable = Nothing
Dim count As Integer = - 1
If useDataSource = False Then
' ViewState must have a non-null value for ItemCount because this is checked
' in CreateChildControls.
count = CInt(ViewState("ItemCount"))
If count <> - 1 Then
dataSource = New DummyDataSource(count)
End If
Else
dataSource = Me._dataSource
End If
If Not (dataSource Is Nothing) Then
Dim table As New Table()
Controls.Add(table)
Dim selectedItemIndex As Integer = SelectedIndex
Dim index As Integer = 0
count = 0
Dim dataItem As Object
For Each dataItem In dataSource
Dim itemType As ListItemType = ListItemType.Item
If index = selectedItemIndex Then
itemType = ListItemType.SelectedItem
Else
If index Mod 2 <> 0 Then
itemType = ListItemType.AlternatingItem
End If
End If
CreateItem(table, index, itemType, useDataSource, dataItem)
count += 1
index += 1
Next dataItem
End If
If useDataSource Then
' Save the number of items contained for use in round trips.
If Not (dataSource Is Nothing) Then
ViewState("ItemCount") = count
Else
ViewState("ItemCount") = -1
End If
End If
End Sub
Protected Overrides Function CreateControlStyle() As Style
' Since the TemplatedList control renders an HTML table,
' an instance of the TableStyle class is used as the control style.
Dim style As New TableStyle(ViewState)
' Set up default initial state.
style.CellSpacing = 0
Return style
End Function
Private Function CreateItem(table As Table, itemIndex As Integer, itemType As ListItemType, dataBind As Boolean, dataItem As Object) As TemplatedListItem
Dim item As New TemplatedListItem(itemIndex, itemType)
Dim e As New TemplatedListItemEventArgs(item)
If Not (_itemTemplate Is Nothing) Then
_itemTemplate.InstantiateIn(item.Cells(0))
End If
If dataBind Then
item.DataItem = dataItem
End If
OnItemCreated(e)
table.Rows.Add(item)
If dataBind Then
item.DataBind()
OnItemDataBound(e)
item.DataItem = Nothing
End If
Return item
End Function
Public Overrides Sub DataBind()
' Controls with a data-source property perform their custom data binding
' by overriding DataBind.
' Evaluate any data-binding expressions on the control itself.
MyBase.OnDataBinding(EventArgs.Empty)
' Reset the control state.
Controls.Clear()
ClearChildViewState()
' Create the control hierarchy using the data source.
CreateControlHierarchy(True)
ChildControlsCreated = True
TrackViewState()
End Sub
Protected Overrides Sub LoadViewState(savedState As Object)
' Customized state management to handle saving state of contained objects.
If Not (savedState Is Nothing) Then
Dim myState As Object() = CType(savedState, Object())
If Not (myState(0) Is Nothing) Then
MyBase.LoadViewState(myState(0))
End If
If Not (myState(1) Is Nothing) Then
CType(ItemStyle, IStateManager).LoadViewState(myState(1))
End If
If Not (myState(2) Is Nothing) Then
CType(SelectedItemStyle, IStateManager).LoadViewState(myState(2))
End If
If Not (myState(3) Is Nothing) Then
CType(AlternatingItemStyle, IStateManager).LoadViewState(myState(3))
End If
End If
End Sub
Protected Overrides Function OnBubbleEvent(source As Object, e As EventArgs) As Boolean
' Handle events raised by children by overriding OnBubbleEvent.
Dim handled As Boolean = False
If TypeOf e Is TemplatedListCommandEventArgs Then
Dim ce As TemplatedListCommandEventArgs = CType(e, TemplatedListCommandEventArgs)
OnItemCommand(ce)
handled = True
If String.Compare(ce.CommandName, "Select", True) = 0 Then
SelectedIndex = ce.Item.ItemIndex
OnSelectedIndexChanged(EventArgs.Empty)
End If
End If
Return handled
End Function
Private Sub PrepareControlHierarchy()
If HasControls() = False Then
Return
End If
Debug.Assert(TypeOf Controls(0) Is Table)
Dim table As Table = CType(Controls(0), Table)
table.CopyBaseAttributes(Me)
If ControlStyleCreated Then
table.ApplyStyle(ControlStyle)
End If
' The composite alternating item style; do just one
' merge style on the actual item.
Dim altItemStyle As Style = Nothing
If Not (_alternatingItemStyle Is Nothing) Then
altItemStyle = New TableItemStyle()
altItemStyle.CopyFrom(_itemStyle)
altItemStyle.CopyFrom(_alternatingItemStyle)
Else
altItemStyle = _itemStyle
End If
Dim rowCount As Integer = table.Rows.Count
Dim i As Integer
For i = 0 To rowCount - 1
Dim item As TemplatedListItem = CType(table.Rows(i), TemplatedListItem)
Dim compositeStyle As Style = Nothing
Select Case item.ItemType
Case ListItemType.Item
compositeStyle = _itemStyle
Case ListItemType.AlternatingItem
compositeStyle = altItemStyle
Case ListItemType.SelectedItem
If (True) Then
compositeStyle = New TableItemStyle()
If item.ItemIndex Mod 2 <> 0 Then
compositeStyle.CopyFrom(altItemStyle)
Else
compositeStyle.CopyFrom(_itemStyle)
End If
compositeStyle.CopyFrom(_selectedItemStyle)
End If
End Select
If Not (compositeStyle Is Nothing) Then
item.MergeStyle(compositeStyle)
End If
Next i
End Sub
Protected Overrides Sub Render(writer As HtmlTextWriter)
' Apply styles to the control hierarchy
' and then render it out.
' Apply styles during render phase, so the user can change styles
' after calling DataBind without the property changes ending
' up in view state.
PrepareControlHierarchy()
RenderContents(writer)
End Sub
Protected Overrides Function SaveViewState() As Object
' Customize state management to handle saving state of contained objects such as styles.
Dim baseState As Object = MyBase.SaveViewState()
Dim itemStyleState As Object
Dim selectedItemStyleState As Object
Dim alternatingItemStyleState As Object
If Not (_itemStyle Is Nothing) Then
itemStyleState = CType(_itemStyle, IStateManager).SaveViewState()
Else
itemStyleState = Nothing
End If
If Not (_selectedItemStyle Is Nothing) Then
selectedItemStyleState = CType(_selectedItemStyle, IStateManager).SaveViewState()
Else
selectedItemStyleState = Nothing
End If
If Not (_alternatingItemStyle Is Nothing) Then
alternatingItemStyleState = CType(_alternatingItemStyle, IStateManager).SaveViewState()
Else
alternatingItemStyleState = Nothing
End If
Dim myState(4) As Object
myState(0) = baseState
myState(1) = itemStyleState
myState(2) = selectedItemStyleState
myState(3) = alternatingItemStyleState
Return myState
End Function
Protected Overrides Sub TrackViewState()
' Customize state management to handle saving state of contained objects such as styles.
MyBase.TrackViewState()
If Not (_itemStyle Is Nothing) Then
CType(_itemStyle, IStateManager).TrackViewState()
End If
If Not (_selectedItemStyle Is Nothing) Then
CType(_selectedItemStyle, IStateManager).TrackViewState()
End If
If Not (_alternatingItemStyle Is Nothing) Then
CType(_alternatingItemStyle, IStateManager).TrackViewState()
End If
End Sub
#End Region
End Class
Public Class TemplatedListItem
Inherits TableRow
Implements INamingContainer
Private _itemIndex As Integer
Private _itemType As ListItemType
Private _dataItem As Object
Public Sub New(itemIndex As Integer, itemType As ListItemType)
Me._itemIndex = itemIndex
Me._itemType = itemType
Cells.Add(New TableCell())
End Sub
Public Overridable Property DataItem() As Object
Get
Return _dataItem
End Get
Set
_dataItem = value
End Set
End Property
Public Overridable ReadOnly Property ItemIndex() As Integer
Get
Return _itemIndex
End Get
End Property
Public Overridable ReadOnly Property ItemType() As ListItemType
Get
Return _itemType
End Get
End Property
Protected Overrides Function OnBubbleEvent(source As Object, e As EventArgs) As Boolean
If TypeOf e Is CommandEventArgs Then
' Add the information about Item to CommandEvent.
Dim args As New TemplatedListCommandEventArgs(Me, source, CType(e, CommandEventArgs))
RaiseBubbleEvent(Me, args)
Return True
End If
Return False
End Function
Friend Sub SetItemType(itemType As ListItemType)
Me._itemType = itemType
End Sub
End Class
NotInheritable Public Class TemplatedListCommandEventArgs
Inherits CommandEventArgs
Private _item As TemplatedListItem
Private _commandSource As Object
Public Sub New(item As TemplatedListItem, commandSource As Object, originalArgs As CommandEventArgs)
MyBase.New(originalArgs)
Me._item = item
Me._commandSource = commandSource
End Sub
Public ReadOnly Property Item() As TemplatedListItem
Get
Return _item
End Get
End Property
Public ReadOnly Property CommandSource() As Object
Get
Return _commandSource
End Get
End Property
End Class
Public Delegate Sub TemplatedListCommandEventHandler(source As Object, e As TemplatedListCommandEventArgs)
NotInheritable Public Class TemplatedListItemEventArgs
Inherits EventArgs
Private _item As TemplatedListItem
Public Sub New(item As TemplatedListItem)
Me._item = item
End Sub
Public ReadOnly Property Item() As TemplatedListItem
Get
Return _item
End Get
End Property
End Class
Public Delegate Sub TemplatedListItemEventHandler(sender As Object, e As TemplatedListItemEventArgs)
NotInheritable Friend Class DummyDataSource
Implements ICollection
Private dataItemCount As Integer
Public Sub New(dataItemCount As Integer)
Me.dataItemCount = dataItemCount
End Sub
Public ReadOnly Property Count() As Integer Implements ICollection.Count
Get
Return dataItemCount
End Get
End Property
Public ReadOnly Property IsReadOnly() As Boolean
Get
Return False
End Get
End Property
Public ReadOnly Property IsSynchronized() As Boolean Implements ICollection.IsSynchronized
Get
Return False
End Get
End Property
Public ReadOnly Property SyncRoot() As Object Implements ICollection.SyncRoot
Get
Return Me
End Get
End Property
Public Sub CopyTo(array As Array, index As Integer) Implements ICollection.CopyTo
Dim e As IEnumerator
While e.MoveNext()
array.SetValue(e.Current, index)
index += 1
End While
End Sub
Public Function GetEnumerator() As IEnumerator Implements ICollection.GetEnumerator
Return New DummyDataSourceEnumerator(dataItemCount)
End Function
Private Class DummyDataSourceEnumerator
Implements IEnumerator
Private count As Integer
Private index As Integer
Public Sub New(count As Integer)
Me.count = count
Me.index = - 1
End Sub
Public ReadOnly Property Current() As Object Implements IEnumerator.Current
Get
Return Nothing
End Get
End Property
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
index += 1
Return index < count
End Function
Public Sub Reset() Implements IEnumerator.Reset
Me.index = - 1
End Sub
End Class
End Class
End Namespace
Utilizar el control enlazado a datos en una página
En el ejemplo siguiente se muestra una página ASP.NET que utiliza el control TemplatedList
.
<%@ Page language="C#" %>
<%@ Register TagPrefix="custom" Namespace="CustomControls" Assembly="CustomControls"%>
<html>
<head>
<title>Data-Bound Control Sample</title>
</head>
<body>
<form runat="server">
<h3>TemplatedList Control Sample</h3>
<hr>
<custom:TemplatedList runat="server" id="myList"
Font-Name="Verdana" Font-Size="16pt"
BorderColor="Gray" BorderWidth="1px"
CellSpacing="0" CellPadding="2" GridLines="Both"
onItemCreated="MyList_ItemCreated"
onSelectedIndexChanged="MyList_SelectedIndexChanged">
<ItemStyle ForeColor="Black" BackColor="#EEEEEE"/>
<AlternatingItemStyle BackColor="#DCDCDC"/>
<SelectedItemStyle ForeColor="White" BackColor="#000084"/>
<ItemTemplate>
<asp:Button runat="server" id="selectButton" CommandName="Select"
Text="Select" ForeColor="Blue"></asp:Button>
<asp:Label runat="server" Text='<%# Container.DataItem %>'/>
</ItemTemplate>
</custom:TemplatedList>
<hr>
<asp:Label runat="server" id="infoLabel"></asp:Label>
<hr>
</form>
<script runat="server">
private int selectedIndex = -1;
private void LoadData() {
ArrayList data = new ArrayList();
for (int i = 0; i < 10; i++) {
data.Add("Item " + i);
}
myList.DataSource = data;
myList.DataBind();
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
if (!IsPostBack) {
LoadData();
}
}
protected void MyList_ItemCreated(object sender, TemplatedListItemEventArgs e) {
if (e.Item.ItemType == ListItemType.SelectedItem) {
selectedIndex = e.Item.ItemIndex;
Button selectButton = (Button)e.Item.FindControl("selectButton");
selectButton.Enabled = false;
}
}
protected void MyList_SelectedIndexChanged(object sender, EventArgs e) {
if (selectedIndex != -1) {
Control item = myList.Controls[0].Controls[selectedIndex];
Button selectButton = (Button)item.FindControl("selectButton");
selectButton.Enabled = true;
}
selectedIndex = myList.SelectedIndex;
infoLabel.Text = "SelectedIndex: " + selectedIndex;
if (selectedIndex != -1) {
Control item = myList.Controls[0].Controls[selectedIndex];
Button selectButton = (Button)item.FindControl("selectButton");
selectButton.Enabled = false;
}
}
</script>
</body>
</html>
[Visual Basic]
<%@ Page language="VB"%>
<%@ Register TagPrefix="custom" Namespace="CustomControls" Assembly="CustomControls"%>
<html>
<head>
<title>Data-Bound Control Sample</title>
</head>
<body>
<form runat="server">
<h3>TemplatedList Control Sample</h3>
<hr>
<custom:TemplatedList runat="server" id="myList"
Font-Name="Verdana" Font-Size="16pt"
BorderColor="Gray" BorderWidth="1px"
CellSpacing="0" CellPadding="2" GridLines="Both"
onItemCreated="MyList_ItemCreated"
onSelectedIndexChanged="MyList_SelectedIndexChanged">
<ItemStyle ForeColor="Black" BackColor="#EEEEEE"/>
<AlternatingItemStyle BackColor="#DCDCDC"/>
<SelectedItemStyle ForeColor="White" BackColor="#000084"/>
<ItemTemplate>
<asp:Button runat="server" id="selectButton" CommandName="Select"
Text="Select" ForeColor="Blue"></asp:Button>
<asp:Label runat="server" Text='<%# Container.DataItem %>'/>
</ItemTemplate>
</custom:TemplatedList>
<hr>
<asp:Label runat="server" id="infoLabel"></asp:Label>
<hr>
</form>
<script runat="server">
Private selectedIndex As Integer = - 1
Private Sub LoadData()
Dim data As New ArrayList()
Dim i As Integer
For i = 0 To 9
data.Add("Item " & i)
Next i
myList.DataSource = data
myList.DataBind()
End Sub
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
If Not IsPostBack Then
LoadData()
End If
End Sub
Protected Sub MyList_ItemCreated(sender As Object, e As TemplatedListItemEventArgs)
If e.Item.ItemType = ListItemType.SelectedItem Then
selectedIndex = e.Item.ItemIndex
Dim selectButton As Button = CType(e.Item.FindControl("selectButton"), Button)
selectButton.Enabled = False
End If
End Sub
Protected Sub MyList_SelectedIndexChanged(sender As Object, e As EventArgs)
If selectedIndex <> - 1 Then
Dim item As Control = myList.Controls(0).Controls(selectedIndex)
Dim selectButton As Button = CType(item.FindControl("selectButton"), Button)
selectButton.Enabled = True
End If
selectedIndex = myList.SelectedIndex
infoLabel.Text = "SelectedIndex: " + selectedIndex
If selectedIndex <> - 1 Then
Dim item As Control = myList.Controls(0).Controls(selectedIndex)
Dim selectButton As Button = CType(item.FindControl("selectButton"), Button)
selectButton.Enabled = False
End If
End Sub
</script>
</body>
</html>
Vea también
Desarrollar un control enlazado a datos a partir de plantillas