Share via


Web フォーム テンプレート データ連結コントロール デザイナのサンプル

template 宣言のあるデータ連結コントロールのサンプル」に示すテンプレート データ連結コントロール TemplatedList のカスタム デザイナ (TemplatedListDesigner) を実装する例を次に示します。TemplatedListDesigner は次のような概念を含んでいます。

  • デザイン時 HTML の表示
  • テンプレート エディタの実装
  • プロパティのフィルタ処理の実装
  • デザイン時データ連結の実装
'-----------------------------------------------------------------------
' 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;
        }
    }
}

参照

Web フォーム テンプレート エディタの実装 | Web フォーム データ連結コントロール デザイナの実装 | カスタム デザイナ | Web フォームのデザイン時サポート