Ejemplo de diseñador de controles de formularios Web Forms enlazados a datos con plantillas
En el siguiente ejemplo se implementa un diseñador personalizado (TemplatedListDesigner
) para el control enlazado a datos a partir de plantillas TemplatedList
, que se describe en Ejemplo de control enlazado a datos a partir de plantillas.
- Procesamiento del código HTML en tiempo de diseño.
- Implementación de un editor de plantillas.
- Implementación del filtrado de propiedades.
- Implementación del enlace a datos en tiempo de diseño.
'-----------------------------------------------------------------------
' TemplatedListDesigner.vb.
'------------------------------------------------------------------------
Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Data
Imports System.Diagnostics
Imports System.Web.UI
Imports System.Web.UI.Design
Imports System.Web.UI.WebControls
Imports CustomControls
Namespace CustomControls.Design
Public Class TemplatedListDesigner
Inherits TemplatedControlDesigner
Implements IDataSourceProvider
Private dummyDataTable As DataTable
Private designTimeDataTable As DataTable
Private templateVerbs() As TemplateEditingVerb
Private templateVerbsDirty As Boolean
Public Sub New()
templateVerbsDirty = True
End Sub
Public Overrides ReadOnly Property AllowResize() As Boolean
Get
' When templates are not defined, render a read-only fixed-
' size block. Once templates are defined or are being edited, the control should allow
' resizing.
Return TemplatesExist Or InTemplateMode
End Get
End Property
Public Property DataSource() As String
Get
Dim binding As DataBinding = DataBindings("DataSource")
If Not (binding Is Nothing) Then
Return binding.Expression
End If
Return [String].Empty
End Get
Set
If value Is Nothing Or value.Length = 0 Then
DataBindings.Remove("DataSource")
Else
Dim binding As DataBinding = DataBindings("DataSource")
If binding Is Nothing Then
binding = New DataBinding("DataSource", GetType(IEnumerable), value)
Else
binding.Expression = value
End If
DataBindings.Add(binding)
End If
OnDataSourceChanged()
OnBindingsCollectionChanged("DataSource")
End Set
End Property
Public Overrides ReadOnly Property DesignTimeHtmlRequiresLoadComplete() As Boolean
Get
' If there is a data source, look it up in the container
' and require the document to be loaded completely.
Return DataSource.Length <> 0
End Get
End Property
Protected ReadOnly Property TemplatesExist() As Boolean
Get
Return Not (CType(Component, TemplatedList).ItemTemplate Is Nothing)
End Get
End Property
Protected Overrides Function CreateTemplateEditingFrame(verb As TemplateEditingVerb) As ITemplateEditingFrame
Dim teService As ITemplateEditingService = CType(GetService(GetType(ITemplateEditingService)), ITemplateEditingService)
Debug.Assert( Not (teService Is Nothing), "How did we get this far without an ITemplateEditingService")
Debug.Assert((verb.Index = 0))
Dim templateNames() As String = {"ItemTemplate"}
Dim templateStyles() As Style = {CType(Component, TemplatedList).ItemStyle}
Dim editingFrame As ITemplateEditingFrame = teService.CreateFrame(Me, verb.Text, templateNames, CType(Component, TemplatedList).ControlStyle, templateStyles)
Return editingFrame
End Function
Protected Overloads Overrides Sub Dispose(disposing As Boolean)
If disposing
DisposeTemplateVerbs()
End If
MyBase.Dispose(disposing)
End Sub
Private Sub DisposeTemplateVerbs()
If Not (templateVerbs Is Nothing) Then
templateVerbs(0).Dispose()
templateVerbs = Nothing
templateVerbsDirty = True
End If
End Sub
Protected Overrides Function GetCachedTemplateEditingVerbs() As TemplateEditingVerb()
If templateVerbsDirty = True Then
DisposeTemplateVerbs()
templateVerbs = New TemplateEditingVerb(1) {}
templateVerbs(0) = New TemplateEditingVerb("Item Template", 0, Me)
templateVerbsDirty = False
End If
Return templateVerbs
End Function
Protected Function GetDesignTimeDataSource(minimumRows As Integer, ByRef dummyDataSource As Boolean) As IEnumerable
dummyDataSource = False
Dim selectedDataSource As IEnumerable = CType(Me, IDataSourceProvider).GetResolvedSelectedDataSource()
Dim dataTable As DataTable = designTimeDataTable
' Use the data table corresponding to the selected data source
' if possible.
If dataTable Is Nothing Then
If Not (selectedDataSource Is Nothing) Then
designTimeDataTable = DesignTimeData.CreateSampleDataTable(selectedDataSource)
dataTable = designTimeDataTable
End If
If dataTable Is Nothing Then
' Fall back on a dummy data source if a sample data-table cannot be created.
If dummyDataTable Is Nothing Then
dummyDataTable = DesignTimeData.CreateDummyDataTable()
End If
dataTable = dummyDataTable
dummyDataSource = True
End If
End If
Dim liveDataSource As IEnumerable = DesignTimeData.GetDesignTimeDataSource(dataTable, minimumRows)
Return liveDataSource
End Function
Public Overrides Function GetDesignTimeHtml() As String
Dim control As TemplatedList = CType(Component, TemplatedList)
Dim designTimeHTML As String = Nothing
Dim hasATemplate As Boolean = Me.TemplatesExist
If hasATemplate Then
Dim dummyDataSource As Boolean
Dim designTimeDataSource As IEnumerable = GetDesignTimeDataSource(5, dummyDataSource)
Try
control.DataSource = designTimeDataSource
control.DataBind()
designTimeHTML = MyBase.GetDesignTimeHtml()
Finally
control.DataSource = Nothing
End Try
Else
designTimeHTML = GetEmptyDesignTimeHtml()
End If
Return designTimeHTML
End Function
Protected Overrides Function GetEmptyDesignTimeHtml() As String
Dim _text As String
If CanEnterTemplateMode Then
_text = "Right-click and choose a set of templates to edit their content.<br>The ItemTemplate is required."
Else
_text = "Switch to HTML view to edit the control's templates.<br>The ItemTemplate is required."
End If
Return CreatePlaceHolderDesignTimeHtml(_text)
End Function
Protected Overrides Function GetErrorDesignTimeHtml(e As Exception) As String
Debug.Fail(e.ToString())
Return CreatePlaceHolderDesignTimeHtml("There was an error rendering the control.<br>Check to make sure all properties are valid.")
End Function
Public Overrides Function GetTemplateContainerDataSource(templateName As String) As IEnumerable
Return CType(Me, IDataSourceProvider).GetResolvedSelectedDataSource()
End Function
Public Overrides Function GetTemplateContainerDataItemProperty(templateName As String) As String
Return "DataItem"
End Function
Public Overrides Function GetTemplateContent(editingFrame As ITemplateEditingFrame, templateName As String, ByRef allowEditing As Boolean) As String
Debug.Assert((editingFrame.Verb.Index = 0))
Debug.Assert(templateName.Equals("ItemTemplate"))
allowEditing = True
Dim template As ITemplate = CType(Component, TemplatedList).ItemTemplate
Dim templateContent As String = [String].Empty
If Not (template Is Nothing) Then
templateContent = GetTextFromTemplate(template)
End If
Return templateContent
End Function
Public Overrides Sub OnComponentChanged(sender As Object, e As ComponentChangedEventArgs)
If Not (e.Member Is Nothing) Then
Dim memberName As String = e.Member.Name
If memberName.Equals("DataSource") Or memberName.Equals("DataMember") Then
OnDataSourceChanged()
Else
If memberName.Equals("ItemStyle") Then
OnStylesChanged()
End If
End If
End If
MyBase.OnComponentChanged(sender, e)
End Sub
Protected Overridable Sub OnDataSourceChanged()
designTimeDataTable = Nothing
End Sub
Protected Sub OnStylesChanged()
OnTemplateEditingVerbsChanged()
End Sub
Protected Sub OnTemplateEditingVerbsChanged()
templateVerbsDirty = True
End Sub
Protected Overrides Sub PreFilterProperties(properties As IDictionary)
MyBase.PreFilterProperties(properties)
Dim prop As PropertyDescriptor
prop = CType(properties("DataSource"), PropertyDescriptor)
Debug.Assert(( Not (prop Is Nothing)))
prop = TypeDescriptor.CreateProperty(Me.GetType(), prop, New Attribute() {New TypeConverterAttribute(GetType(DataSourceConverter))})
properties("DataSource") = prop
End Sub
Public Overrides Sub SetTemplateContent(editingFrame As ITemplateEditingFrame, templateName As String, templateContent As String)
Debug.Assert((editingFrame.Verb.Index = 0))
Debug.Assert(templateName.Equals("ItemTemplate"))
Dim template As ITemplate = Nothing
If Not (templateContent Is Nothing) And templateContent.Length <> 0 Then
template = GetTemplateFromText(templateContent)
End If
CType(Component, TemplatedList).ItemTemplate = template
End Sub
Function GetResolvedSelectedDataSource() As IEnumerable Implements IDataSourceProvider.GetResolvedSelectedDataSource
Return CType(CType(Me, IDataSourceProvider).GetSelectedDataSource(), IEnumerable)
End Function
Function GetSelectedDataSource() As Object Implements IDataSourceProvider.GetSelectedDataSource
Dim selectedDataSource As Object = Nothing
Dim dataSource As String = Nothing
Dim binding As DataBinding = DataBindings("DataSource")
If Not (binding Is Nothing) Then
dataSource = binding.Expression
End If
If Not (dataSource Is Nothing) Then
Dim componentSite As ISite = Component.Site
If Not (componentSite Is Nothing) Then
Dim container As IContainer = CType(componentSite.GetService(GetType(IContainer)), IContainer)
If Not (container Is Nothing) Then
Dim comp As IComponent = container.Components(dataSource)
If TypeOf comp Is IEnumerable Then
selectedDataSource = comp
End If
End If
End If
End If
Return selectedDataSource
End Function
End Class
End Namespace
[C#]
//-----------------------------------------------------------------------
// TemplatedListDesigner.cs.
//------------------------------------------------------------------------
namespace CustomControls.Design {
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Diagnostics;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;
using CustomControls;
public class TemplatedListDesigner : TemplatedControlDesigner, IDataSourceProvider {
private DataTable dummyDataTable;
private DataTable designTimeDataTable;
private TemplateEditingVerb[] templateVerbs;
private bool templateVerbsDirty;
public TemplatedListDesigner() {
templateVerbsDirty = true;
}
public override bool AllowResize {
get {
// When templates are not defined, render a read-only fixed-
// size block. Once templates are defined or are being edited, the control should allow
// resizing.
return TemplatesExist || InTemplateMode;
}
}
public string DataSource {
get {
DataBinding binding = DataBindings["DataSource"];
if (binding != null) {
return binding.Expression;
}
return String.Empty;
}
set {
if ((value == null) || (value.Length == 0)) {
DataBindings.Remove("DataSource");
}
else {
DataBinding binding = DataBindings["DataSource"];
if (binding == null) {
binding = new DataBinding("DataSource", typeof(IEnumerable), value);
}
else {
binding.Expression = value;
}
DataBindings.Add(binding);
}
OnDataSourceChanged();
OnBindingsCollectionChanged("DataSource");
}
}
public override bool DesignTimeHtmlRequiresLoadComplete {
get {
// If there is a data source, look it up in the container
// and require the document to be loaded completely.
return (DataSource.Length != 0);
}
}
protected bool TemplatesExist {
get {
return (((TemplatedList)Component).ItemTemplate != null);
}
}
protected override ITemplateEditingFrame CreateTemplateEditingFrame(TemplateEditingVerb verb) {
ITemplateEditingService teService = (ITemplateEditingService)GetService(typeof(ITemplateEditingService));
Debug.Assert(teService != null, "How did we get this far without an ITemplateEditingService");
Debug.Assert(verb.Index == 0);
string[] templateNames = new string[] { "ItemTemplate" };
Style[] templateStyles = new Style[] { ((TemplatedList)Component).ItemStyle };
ITemplateEditingFrame editingFrame =
teService.CreateFrame(this, verb.Text, templateNames, ((TemplatedList)Component).ControlStyle, templateStyles);
return editingFrame;
}
protected override void Dispose(bool disposing) {
if (disposing) {
DisposeTemplateVerbs();
}
base.Dispose(disposing);
}
private void DisposeTemplateVerbs() {
if (templateVerbs != null) {
templateVerbs[0].Dispose();
templateVerbs = null;
templateVerbsDirty = true;
}
}
protected override TemplateEditingVerb[] GetCachedTemplateEditingVerbs() {
if (templateVerbsDirty == true) {
DisposeTemplateVerbs();
templateVerbs = new TemplateEditingVerb[1];
templateVerbs[0] = new TemplateEditingVerb("Item Template", 0, this);
templateVerbsDirty = false;
}
return templateVerbs;
}
protected IEnumerable GetDesignTimeDataSource(int minimumRows, out bool dummyDataSource) {
dummyDataSource = false;
IEnumerable selectedDataSource = ((IDataSourceProvider)this).GetResolvedSelectedDataSource();
DataTable dataTable = designTimeDataTable;
// Use the data table corresponding to the selected data source
// if possible.
if (dataTable == null) {
if (selectedDataSource != null) {
designTimeDataTable = DesignTimeData.CreateSampleDataTable(selectedDataSource);
dataTable = designTimeDataTable;
}
if (dataTable == null) {
// Fall back on a dummy data source if a sample data table cannot be created.
if (dummyDataTable == null) {
dummyDataTable = DesignTimeData.CreateDummyDataTable();
}
dataTable = dummyDataTable;
dummyDataSource = true;
}
}
IEnumerable liveDataSource = DesignTimeData.GetDesignTimeDataSource(dataTable, minimumRows);
return liveDataSource;
}
public override string GetDesignTimeHtml() {
TemplatedList control = (TemplatedList)Component;
string designTimeHTML = null;
bool hasATemplate = this.TemplatesExist;
if (hasATemplate) {
bool dummyDataSource;
IEnumerable designTimeDataSource = GetDesignTimeDataSource(5, out dummyDataSource);
try {
control.DataSource = designTimeDataSource;
control.DataBind();
designTimeHTML = base.GetDesignTimeHtml();
}
finally {
control.DataSource = null;
}
}
else {
designTimeHTML = GetEmptyDesignTimeHtml();
}
return designTimeHTML;
}
protected override string GetEmptyDesignTimeHtml() {
string text;
if (CanEnterTemplateMode) {
text = "Right-click and choose a set of templates to edit their content.<br>The ItemTemplate is required.";
}
else {
text = "Switch to HTML view to edit the control's templates.<br>The ItemTemplate is required.";
}
return CreatePlaceHolderDesignTimeHtml(text);
}
protected override string GetErrorDesignTimeHtml(Exception e) {
Debug.Fail(e.ToString());
return CreatePlaceHolderDesignTimeHtml("There was an error rendering the control.<br>Check to make sure all properties are valid.");
}
public override IEnumerable GetTemplateContainerDataSource(string templateName) {
return ((IDataSourceProvider)this).GetResolvedSelectedDataSource();
}
public override string GetTemplateContainerDataItemProperty(string templateName) {
return "DataItem";
}
public override string GetTemplateContent(ITemplateEditingFrame editingFrame, string templateName, out bool allowEditing) {
Debug.Assert(editingFrame.Verb.Index == 0);
Debug.Assert(templateName.Equals("ItemTemplate"));
allowEditing = true;
ITemplate template = ((TemplatedList)Component).ItemTemplate;
string templateContent = String.Empty;
if (template != null) {
templateContent = GetTextFromTemplate(template);
}
return templateContent;
}
public override void OnComponentChanged(object sender, ComponentChangedEventArgs e) {
if (e.Member != null) {
string memberName = e.Member.Name;
if (memberName.Equals("DataSource") || memberName.Equals("DataMember")) {
OnDataSourceChanged();
}
else if (memberName.Equals("ItemStyle")) {
OnStylesChanged();
}
}
base.OnComponentChanged(sender, e);
}
protected virtual void OnDataSourceChanged() {
designTimeDataTable = null;
}
protected void OnStylesChanged() {
OnTemplateEditingVerbsChanged();
}
protected void OnTemplateEditingVerbsChanged() {
templateVerbsDirty = true;
}
protected override void PreFilterProperties(IDictionary properties) {
base.PreFilterProperties(properties);
PropertyDescriptor prop;
prop = (PropertyDescriptor)properties["DataSource"];
Debug.Assert(prop != null);
prop = TypeDescriptor.CreateProperty(this.GetType(), prop,
new Attribute[] {
new TypeConverterAttribute(typeof(DataSourceConverter))
});
properties["DataSource"] = prop;
}
public override void SetTemplateContent(ITemplateEditingFrame editingFrame, string templateName, string templateContent) {
Debug.Assert(editingFrame.Verb.Index == 0);
Debug.Assert(templateName.Equals("ItemTemplate"));
ITemplate template = null;
if ((templateContent != null) && (templateContent.Length != 0)) {
template = GetTemplateFromText(templateContent);
}
((TemplatedList)Component).ItemTemplate = template;
}
IEnumerable IDataSourceProvider.GetResolvedSelectedDataSource() {
return (IEnumerable)((IDataSourceProvider)this).GetSelectedDataSource();
}
object IDataSourceProvider.GetSelectedDataSource() {
object selectedDataSource = null;
string dataSource = null;
DataBinding binding = DataBindings["DataSource"];
if (binding != null) {
dataSource = binding.Expression;
}
if (dataSource != null) {
ISite componentSite = Component.Site;
if (componentSite != null) {
IContainer container = (IContainer)componentSite.GetService(typeof(IContainer));
if (container != null) {
IComponent comp = container.Components[dataSource];
if (comp is IEnumerable) {
selectedDataSource = comp;
}
}
}
}
return selectedDataSource;
}
}
}
Vea también
Implementar un editor de plantillas de formularios Web Forms | Implementar un diseñador de controles enlazados a datos de formularios Web Forms | Diseñadores personalizados | Compatibilidad en tiempo de diseño con formularios Web Forms