Share via


子控件的类型化样式示例

更新:2007 年 11 月

此示例演示如何创建一个名为 StyledRegister 的控件,该控件会在复合控件中实现强类型样式属性。这些属性使页开发人员能够自定义复合控件子控件的外观。类型化样式还允许轻松缩放复合控件。随着更多的子控件添加到复合控件中,公开复合控件中每个子控件的众多属性变得越来越难管理。此时可以将这许多属性封装在一个样式属性中。

示例中的 StyledRegister 控件与 复合 Web 控件示例 中所描述的 Register 控件类似。StyledRegister 控件有两个 TextBox 子控件和一个 Button 子控件。StyledRegister 类公开 ButtonStyle 和 TextBoxStyle 属性,以使页开发人员能够设置 TextBoxButton 子控件的 FontForeColor 和其他与样式相关的属性。

页开发人员可以按下面的示例所示在 StyledRegister 控件中设置子控件的 Font-Names、ForeColor 和 BackColor 属性:

<aspSample:StyledRegister ID="StyledRegister1" runat="server">
  <TextBoxStyle Font-Names="Arial" BorderStyle="Solid"  
    ForeColor="#804000"></TextBoxStyle>
  <ButtonStyle Font-Names="Arial" BorderStyle="Outset" 
    BackColor="Silver"></ButtonStyle>
</aspSample:StyledRegister>

如上面的示例所示,类型化样式属性作为控件标记中的子元素保存。有关实现以这种方法保存的属性的信息,请参见 服务器控件属性示例 中的 Author 属性实现。

类型化样式是 Style 类型的属性,或是从 Style 派生的类型的属性。Style 类用于公开与外观相关的属性,如 FontForeColorBackColorWebControl 类的 ControlStyle 属性为 Style 类型的属性。Web 控件的 FontForeColorBackColor 属性是 ControlStyle 属性的子属性,尽管这些属性也是作为 WebControl 类的顶级属性公开的。

由于 Style 类具有子属性,因此 Style 类型的属性需要自定义状态管理,如 自定义属性状态管理示例 中所述。有关类型化样式的实现详细信息,将在本主题后面的“代码讨论”一节中进行描述。

StyledRegister 控件的代码清单

' StyledRegister.vb
Option Strict On
Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Security.Permissions
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls

Namespace Samples.AspNet.VB.Controls
    < _
    AspNetHostingPermission(SecurityAction.Demand, _
        Level:=AspNetHostingPermissionLevel.Minimal), _
    AspNetHostingPermission(SecurityAction.InheritanceDemand, _
        Level:=AspNetHostingPermissionLevel.Minimal), _
    DefaultEvent("Submit"), _
    DefaultProperty("ButtonText"), _
    ToolboxData("<{0}:Register runat=""server""> </{0}:Register>") _
    > _
    Public Class StyledRegister
        Inherits CompositeControl

        Private submitButton As Button
        Private nameTextBox As TextBox
        Private nameLabel As Label
        Private emailTextBox As TextBox
        Private emailLabel As Label
        Private emailValidator As RequiredFieldValidator
        Private nameValidator As RequiredFieldValidator

        Private Shared ReadOnly EventSubmitKey As New Object()

        Private buttonStyleValue As Style
        Private textBoxStyleValue As Style

#Region "Properties delegated to child controls"
        < _
        Bindable(True), _
        Category("Appearance"), _
        DefaultValue(""), _
        Description("The text to display on the Button.") _
        > _
        Public Property ButtonText() As String
            Get
                EnsureChildControls()
                Return submitButton.Text
            End Get
            Set(ByVal value As String)
                EnsureChildControls()
                submitButton.Text = value
            End Set
        End Property

        < _
        Bindable(True), _
        Category("Default"), _
        DefaultValue(""), _
        Description("The user name.") _
        > _
        Public Property Name() As String
            Get
                EnsureChildControls()
                Return nameTextBox.Text
            End Get
            Set(ByVal value As String)
                EnsureChildControls()
                nameTextBox.Text = value
            End Set
        End Property

        < _
        Bindable(True), _
        Category("Appearance"), _
        DefaultValue(""), _
        Description("The error message of the name validator.") _
        > _
        Public Property NameErrorMessage() As String
            Get
                EnsureChildControls()
                Return nameValidator.ErrorMessage
            End Get
            Set(ByVal value As String)
                EnsureChildControls()
                nameValidator.ErrorMessage = value
                nameValidator.ToolTip = value
            End Set
        End Property

        < _
        Bindable(True), _
        Category("Appearance"), _
        DefaultValue(""), _
        Description("The text for the name Label.") _
        > _
        Public Property NameLabelText() As String
            Get
                EnsureChildControls()
                Return nameLabel.Text
            End Get
            Set(ByVal value As String)
                EnsureChildControls()
                nameLabel.Text = value
            End Set
        End Property

        < _
        Bindable(True), _
        Category("Default"), _
        DefaultValue(""), _
        Description("The e-mail address.") _
        > _
        Public Property Email() As String
            Get
                EnsureChildControls()
                Return emailTextBox.Text
            End Get
            Set(ByVal value As String)
                EnsureChildControls()
                emailTextBox.Text = value
            End Set
        End Property

        < _
        Bindable(True), _
        Category("Appearance"), _
        DefaultValue(""), _
        Description("Error message of the e-mail validator.") _
        > _
        Public Property EmailErrorMessage() As String
            Get
                EnsureChildControls()
                Return emailValidator.ErrorMessage
            End Get
            Set(ByVal value As String)
                EnsureChildControls()
                emailValidator.ErrorMessage = value
                emailValidator.ToolTip = value
            End Set
        End Property
        < _
        Bindable(True), _
        Category("Appearance"), _
        DefaultValue(""), _
        Description("The text for the e-mail Label.") _
        > _
        Public Property EmailLabelText() As String
            Get
                EnsureChildControls()
                Return emailLabel.Text
            End Get
            Set(ByVal value As String)
                EnsureChildControls()
                emailLabel.Text = value
            End Set
        End Property
#End Region

#Region "Typed Style properties"
        < _
        Category("Styles"), _
        DefaultValue(GetType(Style), Nothing), _
        DesignerSerializationVisibility( _
            DesignerSerializationVisibility.Content), _
        PersistenceMode(PersistenceMode.InnerProperty), _
        Description( _
            "The strongly typed style for the Button child control.") _
        > _
        Public Overridable ReadOnly Property ButtonStyle() As Style
            Get
                If buttonStyleValue Is Nothing Then
                    buttonStyleValue = New Style
                    If IsTrackingViewState Then
                        CType(buttonStyleValue, _
                            IStateManager).TrackViewState()
                    End If
                End If
                Return buttonStyleValue
            End Get
        End Property

        < _
        Category("Styles"), _
        DefaultValue(GetType(Style), Nothing), _
        DesignerSerializationVisibility( _
            DesignerSerializationVisibility.Content), _
        PersistenceMode(PersistenceMode.InnerProperty), _
        Description( _
            "The strongly typed style for the TextBox child control.") _
        > _
        Public Overridable ReadOnly Property TextBoxStyle() As Style
            Get
                If textBoxStyleValue Is Nothing Then
                    textBoxStyleValue = New Style
                    If IsTrackingViewState Then
                        CType(textBoxStyleValue, _
                            IStateManager).TrackViewState()
                    End If
                End If
                Return textBoxStyleValue
            End Get
        End Property
#End Region

#Region "Event definition"
        < _
        Category("Action"), _
        Description("Raised when the user clicks the button.") _
        > _
        Public Custom Event Submit As EventHandler
            AddHandler(ByVal value As EventHandler)
                Events.AddHandler(EventSubmitKey, value)
            End AddHandler
            RemoveHandler(ByVal value As EventHandler)
                Events.RemoveHandler(EventSubmitKey, value)
            End RemoveHandler
            RaiseEvent(ByVal sender As Object, _
                ByVal e As System.EventArgs)
                CType(Events(EventSubmitKey), _
                    EventHandler).Invoke(sender, e)
            End RaiseEvent
        End Event

        ' The method that raises the Submit event.
        Protected Overridable Sub OnSubmit(ByVal e As EventArgs)
            Dim submitHandler As EventHandler = _
                CType(Events(EventSubmitKey), EventHandler)
            If submitHandler IsNot Nothing Then
                submitHandler(Me, e)
            End If
        End Sub

        ' Handles the Click event of the Button and raises
        ' the Submit event.
        Private Sub submitButton_Click(ByVal source As Object, _
            ByVal e As EventArgs)
            OnSubmit(EventArgs.Empty)
        End Sub
#End Region

#Region "Overridden methods"
        Protected Overrides Sub CreateChildControls()
            Controls.Clear()

            nameLabel = New Label()

            nameTextBox = New TextBox()
            nameTextBox.ID = "nameTextBox"

            nameValidator = New RequiredFieldValidator()
            nameValidator.ID = "validator1"
            nameValidator.ControlToValidate = nameTextBox.ID
            nameValidator.Text = "*"
            nameValidator.Display = ValidatorDisplay.Static

            emailLabel = New Label()

            emailTextBox = New TextBox()
            emailTextBox.ID = "emailTextBox"

            emailValidator = New RequiredFieldValidator()
            emailValidator.ID = "validator2"
            emailValidator.ControlToValidate = emailTextBox.ID
            emailValidator.Text = "*"
            emailValidator.Display = ValidatorDisplay.Static

            submitButton = New Button()
            submitButton.ID = "button1"
            AddHandler submitButton.Click, _
                AddressOf submitButton_Click

            Me.Controls.Add(nameLabel)
            Me.Controls.Add(nameTextBox)
            Me.Controls.Add(nameValidator)
            Me.Controls.Add(emailLabel)
            Me.Controls.Add(emailTextBox)
            Me.Controls.Add(emailValidator)
            Me.Controls.Add(submitButton)
        End Sub

        Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
            AddAttributesToRender(writer)

            writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, _
                "1", False)
            writer.RenderBeginTag(HtmlTextWriterTag.Table)

            If buttonStyleValue IsNot Nothing Then
                submitButton.ApplyStyle(buttonStyleValue)
            End If

            If textBoxStyleValue IsNot Nothing Then
                nameTextBox.ApplyStyle(textBoxStyleValue)
                emailTextBox.ApplyStyle(textBoxStyleValue)
            End If

            writer.RenderBeginTag(HtmlTextWriterTag.Tr)
            writer.RenderBeginTag(HtmlTextWriterTag.Td)
            nameLabel.RenderControl(writer)
            writer.RenderEndTag()  ' Renders the </td> tag.
            writer.RenderBeginTag(HtmlTextWriterTag.Td)
            nameTextBox.RenderControl(writer)
            writer.RenderEndTag()  'closing Td
            writer.RenderBeginTag(HtmlTextWriterTag.Td)
            nameValidator.RenderControl(writer)
            writer.RenderEndTag()  'closing Td
            writer.RenderEndTag()  'closing Tr

            writer.RenderBeginTag(HtmlTextWriterTag.Tr)
            writer.RenderBeginTag(HtmlTextWriterTag.Td)
            emailLabel.RenderControl(writer)
            writer.RenderEndTag()  'closing Td
            writer.RenderBeginTag(HtmlTextWriterTag.Td)
            emailTextBox.RenderControl(writer)
            writer.RenderEndTag()  'closing Td
            writer.RenderBeginTag(HtmlTextWriterTag.Td)
            emailValidator.RenderControl(writer)
            writer.RenderEndTag()  'closing Td
            writer.RenderEndTag()  'closing Tr

            writer.RenderBeginTag(HtmlTextWriterTag.Tr)
            writer.AddAttribute(HtmlTextWriterAttribute.Colspan, _
                "2", False)
            writer.AddAttribute(HtmlTextWriterAttribute.Align, _
                "right", False)
            writer.RenderBeginTag(HtmlTextWriterTag.Td)
            submitButton.RenderControl(writer)
            writer.RenderEndTag()  'closing Td
            writer.RenderBeginTag(HtmlTextWriterTag.Td)
            writer.Write("&nbsp")
            writer.RenderEndTag()  'closing Td
            writer.RenderEndTag()  'closing Tr

            writer.RenderEndTag()  'closing Table
        End Sub

        Protected Overrides Sub RecreateChildControls()
            EnsureChildControls()
        End Sub

#End Region

#Region "Custom state management"
        Protected Overrides Sub LoadViewState( _
            ByVal savedState As Object)

            If savedState is Nothing Then
                MyBase.LoadViewState(Nothing)
                Return
            Else
                Dim t As Triplet = TryCast(savedState, Triplet)

                If t IsNot Nothing Then
                    ' Always invoke LoadViewState on the base class even if 
                    ' the saved state is null.
                    MyBase.LoadViewState(t.First)

                    If t.Second IsNot Nothing Then
                        CType(buttonStyleValue, _
                            IStateManager).LoadViewState(t.Second)
                    End If

                    If t.Third IsNot Nothing Then
                        CType(textBoxStyleValue, _
                            IStateManager).LoadViewState(t.Third)
                    End If
                Else
                    Throw New ArgumentException("Invalid view state .")
                End If
            End If
        End Sub

        Protected Overrides Function SaveViewState() As Object
            Dim baseState As Object = MyBase.SaveViewState
            Dim buttonStyleState As Object = Nothing
            Dim textBoxStyleState As Object = Nothing

            If buttonStyleValue IsNot Nothing Then
                buttonStyleState = CType(buttonStyleValue, _
                    IStateManager).SaveViewState
            End If

            If textBoxStyleValue IsNot Nothing Then
                textBoxStyleState = CType(textBoxStyleValue, _
                    IStateManager).SaveViewState
            End If
            Return New Triplet(baseState, buttonStyleState, _
                textBoxStyleState)
        End Function

        Protected Overrides Sub TrackViewState()
            MyBase.TrackViewState()
            If buttonStyleValue IsNot Nothing Then
                CType(buttonStyleValue, IStateManager).TrackViewState()
            End If
            If textBoxStyleValue IsNot Nothing Then
                CType(textBoxStyleValue, IStateManager).TrackViewState()
            End If

        End Sub
#End Region
    End Class

End Namespace
// StyledRegister.cs
using System;
using System.ComponentModel;
using System.Drawing;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Samples.AspNet.CS.Controls
{
    [
    AspNetHostingPermission(SecurityAction.Demand,
        Level = AspNetHostingPermissionLevel.Minimal),
    AspNetHostingPermission(SecurityAction.InheritanceDemand, 
        Level=AspNetHostingPermissionLevel.Minimal),
    DefaultEvent("Submit"),
    DefaultProperty("ButtonText"),
    ToolboxData(
        "<{0}:StyledRegister runat=\"server\"> </{0}:StyledRegister>"),
    ]
    public class StyledRegister : CompositeControl
    {
        private Button submitButton;
        private TextBox nameTextBox;
        private Label nameLabel;
        private TextBox emailTextBox;
        private Label emailLabel;
        private RequiredFieldValidator _emailValidator;
        private RequiredFieldValidator _nameValidator;
        private Style _buttonStyle;
        private Style _textBoxStyle;

        private static readonly object EventSubmitKey = new object();

        #region Properties delegated to child controls
        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The text to display on the button.")
        ]
        public string ButtonText
        {
            get
            {
                EnsureChildControls();
                return submitButton.Text;
            }
            set
            {
                EnsureChildControls();
                submitButton.Text = value;
            }
        }

        [
        Bindable(true),
        Category("Default"),
        DefaultValue(""),
        Description("The user name.")
        ]
        public string Name
        {
            get
            {
                EnsureChildControls();
                return nameTextBox.Text;
            }
            set
            {
                EnsureChildControls();
                nameTextBox.Text = value;
            }
        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description(
            "The error message of the name validator.")
        ]
        public string NameErrorMessage
        {
            get
            {
                EnsureChildControls();
                return _nameValidator.ErrorMessage;
            }
            set
            {
                EnsureChildControls();
                _nameValidator.ErrorMessage = value;
                _nameValidator.ToolTip = value;
            }
        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The text for the name label.")
        ]
        public string NameLabelText
        {
            get
            {
                EnsureChildControls();
                return nameLabel.Text;
            }
            set
            {
                EnsureChildControls();
                nameLabel.Text = value;
            }
        }

        [
        Bindable(true),
        Category("Default"),
        DefaultValue(""),
        Description("The e-mail address.")
        ]
        public string Email
        {
            get
            {
                EnsureChildControls();
                return emailTextBox.Text;
            }
            set
            {
                EnsureChildControls();
                emailTextBox.Text = value;
            }
        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description(
            "Error message of the e-mail validator.")
        ]
        public string EmailErrorMessage
        {
            get
            {
                EnsureChildControls();
                return _emailValidator.ErrorMessage;
            }
            set
            {
                EnsureChildControls();
                _emailValidator.ErrorMessage = value;
                _emailValidator.ToolTip = value;
            }
        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The text for the e-mail label.")
        ]
        public string EmailLabelText
        {
            get
            {
                EnsureChildControls();
                return emailLabel.Text;
            }
            set
            {
                EnsureChildControls();
                emailLabel.Text = value;

            }
        }
        #endregion

        #region Typed Style properties
        [
        Category("Styles"),
        DefaultValue(null),
        DesignerSerializationVisibility(
            DesignerSerializationVisibility.Content),
        PersistenceMode(PersistenceMode.InnerProperty),
        Description(
            "The strongly typed style for the Button child control.")
        ]
        public virtual Style ButtonStyle
        {
            get
            {
                if (_buttonStyle == null)
                {
                    _buttonStyle = new Style();
                    if (IsTrackingViewState)
                    {
                        ((IStateManager)_buttonStyle).TrackViewState();
                    }
                }
                return _buttonStyle;
            }
        }

        [
        Category("Styles"),
        DefaultValue(null),
        DesignerSerializationVisibility(
            DesignerSerializationVisibility.Content),
        PersistenceMode(PersistenceMode.InnerProperty),
        Description(
            "The strongly typed style for the TextBox child control.")
        ]
        public virtual Style TextBoxStyle
        {
            get
            {
                if (_textBoxStyle == null)
                {
                    _textBoxStyle = new Style();
                    if (IsTrackingViewState)
                    {
                        ((IStateManager)_textBoxStyle).TrackViewState();
                    }
                }
                return _textBoxStyle;
            }
        }
        #endregion

        #region Event definition
        // The Submit event.
        [
        Category("Action"),
        Description("Raised when the user clicks the button")
        ]
        public event EventHandler Submit
        {
            add
            {
                Events.AddHandler(EventSubmitKey, value);
            }
            remove
            {
                Events.RemoveHandler(EventSubmitKey, value);
            }
        }

        // The method that raises theSubmit event.
        protected virtual void OnSubmit(EventArgs e)
        {
            EventHandler SubmitHandler =
                (EventHandler)Events[EventSubmitKey];
            if (SubmitHandler != null)
            {
                SubmitHandler(this, e);
            }
        }

        // Handles the Click event of the Button and raises
        // the Submit event.
        private void _button_Click(object source, EventArgs e)
        {
            OnSubmit(EventArgs.Empty);
        }
        #endregion

        #region Overridden methods

        protected override void RecreateChildControls()
        {
            EnsureChildControls();
        }


        protected override void CreateChildControls()
        {
            Controls.Clear();

            nameLabel = new Label();

            nameTextBox = new TextBox();
            nameTextBox.ID = "nameTextBox";

            _nameValidator = new RequiredFieldValidator();
            _nameValidator.ID = "validator1";
            _nameValidator.ControlToValidate = nameTextBox.ID;
            _nameValidator.Text = "*";
            _nameValidator.Display = ValidatorDisplay.Static;

            emailLabel = new Label();

            emailTextBox = new TextBox();
            emailTextBox.ID = "emailTextBox";

            _emailValidator = new RequiredFieldValidator();
            _emailValidator.ID = "validator2";
            _emailValidator.ControlToValidate = emailTextBox.ID;
            _emailValidator.Text = "*";
            _emailValidator.Display = ValidatorDisplay.Static;

            submitButton = new Button();
            submitButton.ID = "button1";
            submitButton.Click += new EventHandler(_button_Click);

            this.Controls.Add(nameLabel);
            this.Controls.Add(nameTextBox);
            this.Controls.Add(_nameValidator);
            this.Controls.Add(emailLabel);
            this.Controls.Add(emailTextBox);
            this.Controls.Add(_emailValidator);
            this.Controls.Add(submitButton);
        }

        protected override void Render(HtmlTextWriter writer)
        {
            AddAttributesToRender(writer);

            writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding,
                "1", false);
            writer.RenderBeginTag(HtmlTextWriterTag.Table);

            if (_buttonStyle != null)
            {
                submitButton.ApplyStyle(ButtonStyle);
            }

            if (_textBoxStyle != null)
            {
                nameTextBox.ApplyStyle(TextBoxStyle);
                emailTextBox.ApplyStyle(TextBoxStyle);
            }

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            nameLabel.RenderControl(writer);
            writer.RenderEndTag();  // Closing td.
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            nameTextBox.RenderControl(writer);
            writer.RenderEndTag();  //Closing td.
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            _nameValidator.RenderControl(writer);
            writer.RenderEndTag();  //Closing td.
            writer.RenderEndTag();  //Closing tr.

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            emailLabel.RenderControl(writer);
            writer.RenderEndTag();  //Closing td.
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            emailTextBox.RenderControl(writer);
            writer.RenderEndTag();  //Closing td.
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            _emailValidator.RenderControl(writer);
            writer.RenderEndTag();  //Closing td.
            writer.RenderEndTag();  //Closing tr.

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.AddAttribute(HtmlTextWriterAttribute.Colspan,
                "2", false);
            writer.AddAttribute(HtmlTextWriterAttribute.Align,
                "right", false);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            submitButton.RenderControl(writer);
            writer.RenderEndTag();  //closing td.
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.Write("&nbsp;");
            writer.RenderEndTag();  //closing td.
            writer.RenderEndTag();  //closing tr.

            writer.RenderEndTag();  //closing table.
        }
        #endregion

        #region Custom state management
        protected override void LoadViewState(object savedState)
        {
            if (savedState == null)
            {
                base.LoadViewState(null);
                return;
            }
            else 
            {
                Triplet t = savedState as Triplet;

                if (t != null)
                {
                    // Always invoke LoadViewState on the base class even if 
                    // the saved state is null.
                    base.LoadViewState(t.First);

                    if ((t.Second) != null)
                    {
                        ((IStateManager)ButtonStyle).LoadViewState(t.Second);
                    }

                    if ((t.Third) != null)
                    {
                        ((IStateManager)TextBoxStyle).LoadViewState(t.Third);
                    }
                }
                else
                {
                    throw new ArgumentException("Invalid view state .");
                }
            }
        }

        protected override object SaveViewState()
        {
            object baseState = base.SaveViewState();
            object buttonStyleState = null;
            object textBoxStyleState = null;

            if (_buttonStyle != null)
            {
                buttonStyleState =
                    ((IStateManager)_buttonStyle).SaveViewState();
            }

            if (_textBoxStyle != null)
            {
                textBoxStyleState =
                    ((IStateManager)_textBoxStyle).SaveViewState();
            }

            return new Triplet(baseState,
                buttonStyleState, textBoxStyleState);

        }

        protected override void TrackViewState()
        {
            base.TrackViewState();
            if (_buttonStyle != null)
            {
                ((IStateManager)_buttonStyle).TrackViewState();
            }
            if (_textBoxStyle != null)
            {
                ((IStateManager)_textBoxStyle).TrackViewState();
            }
        }
        #endregion
    }
}

代码讨论

StyledRegister 控件演示为子控件实现类型化样式的主要步骤,如下所述:

  • 定义 Style 类型的属性,或从 Style 派生的类型的属性。

  • 实现样式属性的状态管理。

  • 将样式应用于子控件。

由于 Style 类型实现了 IStateManager 接口,因此定义 Style 类型的属性的模式与 自定义属性状态管理示例 中所描述的模式相同。定义一个类型化样式属性,将其作为一个只读属性存储在私有字段中。在属性的访问器中,只有与属性相对应的字段为 null(在 Visual Basic 中为 Nothing)时,才创建新的 Style 实例。如果控件已启动状态跟踪,则调用新创建的 Style 实例的 TrackViewState 方法。StyledRegister 的 ButtonStyle 和 TextBoxStyle 属性便是使用此技术来定义的。

同样,StyledRegister 中状态管理方法的实现也与 自定义属性状态管理示例 中所描述的相同。在控件的重写后的 TrackViewState 方法中,对基类调用 TrackViewState 方法,并对每个样式属性调用 TrackViewState 方法。在控件的重写后的 SaveViewState 方法中,对基类调用 SaveViewState 方法,并对每个样式属性调用 SaveViewState。从 SaveViewState 返回的状态表示基类和样式属性的组合状态。为了便于在 LoadViewState 方法中进行检索,StyledRegister 控件使用 Triplet 对象来保存组合状态。LoadViewState 方法执行 SaveViewState 方法的反向功能,并在回发时将状态加载到基类和类型化样式中。

实现类型化样式的最后一个步骤是将样式应用于子控件。StyledRegister 控件在保存视图状态后的呈现阶段中执行此步骤,这样,类型化样式的对应状态便不会保存到子控件的视图状态中。如果正在跟踪状态时将类型化样式应用于子控件,这些样式将保存在子控件的视图状态中。由于类型化样式属性会管理其自身的状态,因此这样会使得效率低下。下面的代码摘自 StyledRegister 控件的 Render 方法,用于演示在呈现阶段应用样式的实现模式:

protected override void Render(HtmlTextWriter writer)
{
    // Add code here to set up rendering.    
    if (_buttonStyle != null)
    {
        _button.ApplyStyle(ButtonStyle);
    }

    if (_textBoxStyle != null)
    {
        _nameTextBox.ApplyStyle(TextBoxStyle);
        _emailTextBox.ApplyStyle(TextBoxStyle);
    }
    // Add code here to continue rendering.
} 
Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
    ' Add code here to set up rendering.    
    If buttonStyleValue IsNot Nothing Then
        submitButton.ApplyStyle(buttonStyleValue)
    End If

    If textBoxStyleValue IsNot Nothing Then
        nameTextBox.ApplyStyle(textBoxStyleValue)
        emailTextBox.ApplyStyle(textBoxStyleValue)
    End If
    ' Add code here to continue rendering.
End Sub

StyledRegister 控件的测试页

下面的示例演示一个使用 StyledRegister 控件的 .aspx 页。将在 Submit 事件处理程序中添加代码,以将注册信息输入到数据库中,或写入用户计算机上的 Cookie 中。在成品应用程序中,还需要检查脚本注入式攻击。有关更多信息,请参见脚本侵入概述

<%@ Page Language="VB"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
        Label1.Visible = False
    End Sub

    Sub StyledRegister_Submit(ByVal sender As Object, _
        ByVal e As EventArgs)
        Label1.Text = String.Format( _
            "Thank you, {0}! You are registered.", _
            StyledRegister1.Name)
        Label1.Visible = True
        StyledRegister1.Visible = False
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head id="Head1" runat="server">
    <title>
      StyledRegister Control Test Page
    </title>
  </head>
  <body>
    <form id="form1" runat="server">
      <aspSample:StyledRegister ButtonText="Register" 
        OnSubmit="StyledRegister_Submit" ID="StyledRegister1"
        Runat="server" NameLabelText="Name:" EmailLabelText="Email:" 
        EmailErrorMessage="You must enter your e-mail address."
        NameErrorMessage="You must enter your name." 
        BorderStyle="Solid" BorderWidth="1px" BackColor="#E0E0E0">
        <TextBoxStyle Font-Names="Arial" BorderStyle="Solid" 
          ForeColor="#804000"></TextBoxStyle>
        <ButtonStyle Font-Names="Arial" BorderStyle="Outset" 
          BackColor="Silver"></ButtonStyle>
      </aspSample:StyledRegister>
      <br />
      <asp:Label ID="Label1" Runat="server" Text="Label">
      </asp:Label>
      <asp:ValidationSummary ID="ValidationSummary1" 
        Runat="server" DisplayMode="List" />
    </form>
  </body>
</html>
<%@ Page Language="C#"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
  void Page_Load(object sender, EventArgs e)
  {
    Label1.Visible = false;
  }
  void StyledRegister_Submit(object sender, EventArgs e)
  {
    Label1.Text = String.Format("Thank you, {0}! You are registered.", 
      StyledRegister1.Name);
    Label1.Visible = true;
    StyledRegister1.Visible = false;
  }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head id="Head1" runat="server">
    <title>
      StyledRegister Control Test Page
    </title>
  </head>
  <body>
    <form id="form1" runat="server">
      <aspSample:StyledRegister ButtonText="Register" 
        OnSubmit="StyledRegister_Submit" ID="StyledRegister1"
        Runat="server" NameLabelText="Name:" EmailLabelText="Email:" 
        EmailErrorMessage="You must enter your e-mail address."
        NameErrorMessage="You must enter your name." 
        BorderStyle="Solid" BorderWidth="1px" BackColor="#E0E0E0">
        <TextBoxStyle Font-Names="Arial" BorderStyle="Solid" 
          ForeColor="#804000"></TextBoxStyle>
        <ButtonStyle Font-Names="Arial" BorderStyle="Outset" 
          BackColor="Silver"></ButtonStyle>
      </aspSample:StyledRegister>
      <br />
      <asp:Label ID="Label1" Runat="server" Text="Label">
      </asp:Label>
      <asp:ValidationSummary ID="ValidationSummary1" 
        Runat="server" DisplayMode="List" />
    </form>
  </body>
</html>

生成和使用示例

有关编译和使用自定义控件示例的信息,请参见 生成自定义服务器控件示例

请参见

概念

复合 Web 控件示例

自定义属性状态管理示例

其他资源

开发自定义 ASP.NET 服务器控件