This documentation is archived and is not being maintained.
Web Forms Templated Data-Bound Control Designer Sample
.NET Framework 1.1
The following sample implements a custom designer (TemplatedListDesigner) for the templated data-bound control TemplatedList, which is described in the Templated Data-Bound Control Sample. TemplatedListDesigner illustrates the following concepts:
- Rendering design-time HTML.
- Implementing a template editor.
- Implementing property filtering.
- Implementing design-time data binding.
'----------------------------------------------------------------------- ' 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; } } }
See Also
Implementing a Web Forms Template Editor | Implementing a Web Forms Data-Bound Control Designer | Custom Designers | Design-Time Support for Web Forms
Show: