如何使用行为创建模板化复合控件

时间:2012-10-02 09:57:35

标签: asp.net controltemplate composite-controls

我正在尝试创建一个模板化复合控件,它的工作方式与ASP.Net的“PasswordRecovery”控件类似。

由此,我的意思是用户可以定义自己的模板,但是,通过使用预定义的控件ID,它定义哪个字段,比如电子邮件地址,以及哪个按钮是发送e-邮件。

我试图查看模板化Web服务器控件的文档,但我找不到任何关于向这些控件添加行为的内容。

或者,有没有办法完全改变PasswordRecovery的行为?我想发送一封带有一次性URL的电子邮件来更改密码而不是该控件的常见行为。

2 个答案:

答案 0 :(得分:4)

我回答了一个相关的问题:

https://stackoverflow.com/a/11700540/1268570

但在这个答案中我会更深入。

我将发布一个带有设计支持和自定义行为的模板化服务器控件:

货柜码

[ToolboxItem(false)]
public class TemplatedServerAddressContainer : WebControl, INamingContainer
{
    public string Address { get; protected set; }

    public TemplatedServerAddressContainer(string address)
    {
        this.Address = address;
    }
}
  • 上述控件将负责将您想要发送到控件的数据保持为OUTPUT 。这将是您将在
  • 中实例化模板的控件

服务器控制

[DefaultProperty("Address")]
[ToolboxItem(true)]
[ToolboxData("<{0}:TemplatedServerAddressControl runate=server></{0}:TemplatedServerAddressControl>")]
[Designer(typeof(TemplatedServerAddressDesigner))]
//[ToolboxBitmap(typeof(TemplatedServerAddressControl), "")]
[Description("My templated server control")]
[ParseChildren(true)]
public class TemplatedServerAddressControl : WebControl
{
    private TemplatedServerAddressContainer addressContainer;

    [Bindable(true)]
    [Localizable(true)]
    [DefaultValue(null)]
    [Description("The custom address")]
    [Category("Apperance")]
    [Browsable(true)]
    public string Address
    {
        get
        {
            return (this.ViewState["Address"] ?? string.Empty).ToString();
        }
        set
        {
            this.ViewState["Address"] = value;
        }
    }

    [Browsable(false)]
    [DefaultValue(null)]
    [Description("Address template")]
    [PersistenceMode(PersistenceMode.InnerProperty)]
    [TemplateContainer(typeof(TemplatedServerAddressContainer))]
    [TemplateInstance(TemplateInstance.Multiple)]
    public ITemplate AddressTemplate { get; set; }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public TemplatedServerAddressContainer AddressContainer
    {
        get
        {
            this.EnsureChildControls();

            return this.addressContainer;
        }
        internal set
        {
            this.addressContainer = value;
        }
    }

    public override ControlCollection Controls
    {
        get
        {
            this.EnsureChildControls();

            return base.Controls;
        }
    }

    public override void DataBind()
    {
        this.CreateChildControls();
        this.ChildControlsCreated = true;

        base.DataBind();
    }

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

        if (this.AddressTemplate != null)
        {
            this.addressContainer = new TemplatedServerAddressContainer(this.Address);

            this.AddressTemplate.InstantiateIn(this.addressContainer);
            this.Controls.Add(this.addressContainer);
        }
    }

    protected override bool OnBubbleEvent(object source, EventArgs args)
    {
        if (args is CommandEventArgs)
        {
            var commandArgs = args as CommandEventArgs;

            switch (commandArgs.CommandName)
            {
                case "DoSomething":
                    // place here your custom logic
                    this.Page.Response.Write("Command bubbled");
                    return true;
            }
        }

        return base.OnBubbleEvent(source, args);
    }
}
  • public string Address属性用作作为控件INPUT ,您可以创建执行任务所需的所有输入属性。

  • public ITemplate AddressTemplate { get; set; }这代表您的控件的模板。您为此属性指定的名称将是页面标记中用作模板名称的名称

  • public TemplatedServerAddressContainer AddressContainer此属性仅供设计师支持

  • 为了正确创建子控件,您需要覆盖以下方法和属性:ControlsDataBindCreateChildControls

  • 覆盖OnBubbleEvent,您将能够对来自控件的特定事件作出反应。

设计师支持

public class TemplatedServerAddressDesigner : ControlDesigner
{
    private TemplatedServerAddressControl controlInstance;

    public override void Initialize(IComponent component)
    {
        this.controlInstance = (TemplatedServerAddressControl)component;

        base.Initialize(component);
    }

    public override string GetDesignTimeHtml()
    {
        var sw = new StringWriter();
        var htmlWriter = new HtmlTextWriter(sw);
        var controlTemplate = this.controlInstance.AddressTemplate;

        if (controlTemplate != null)
        {
            this.controlInstance.AddressContainer = new TemplatedServerAddressContainer(
                this.controlInstance.Address
                );
            controlTemplate.InstantiateIn(this.controlInstance.AddressContainer);

            this.controlInstance.DataBind();

            this.controlInstance.RenderControl(htmlWriter);
        }

        return sw.ToString();
    }
}

ASPX标记

<%@ Register Assembly="Msts" Namespace="Msts.Topics.Chapter07___Server_Controls.Lesson02___Server_Controls" TagPrefix="address" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <address:TemplatedServerAddressControl runat="server" ID="addressControl1">
        <AddressTemplate>
            <b>
                Address:
            </b>
            <u>
                <asp:Literal Text="<%# Container.Address %>" runat="server" />
            </u>
            <asp:Button Text="text" runat="server" OnClick="Unnamed_Click" ID="myButton" />
            <br />
            <asp:Button Text="Command bubbled" runat="server" CommandName="DoSomething" OnClick="Unnamed2_Click1" />
        </AddressTemplate>
    </address:TemplatedServerAddressControl>
</asp:Content>

ASPX代码背后

public partial class TemplatedServerAddress : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        this.addressControl1.Address = "Super Cool";
        this.DataBind();
    }

    protected void Unnamed_Click(object sender, EventArgs e)
    {
        this.Response.Write("From custom button" + DateTime.Now.ToString());
    }

    protected void Unnamed2_Click1(object sender, EventArgs e)
    {
        this.Response.Write("From command button " + DateTime.Now.ToString());
    }
}
  • 请注意如何在正确的事件中设置控件的属性而不会出现问题:this.addressControl1.Address = "Super Cool";

  • 请注意您的控件如何处理自定义事件this.Response.Write("From custom button" + DateTime.Now.ToString());

  • 最后,为了向您的控件表明您想要执行某些操作,只需创建一个按钮,控件在控件中公开,如下所示:<asp:Button Text="Command bubbled" runat="server" CommandName="DoSomething" OnClick="Unnamed2_Click1" />可选,您的按钮可以包含在冒泡事件之前处理的事件处理程序。

I uploaded this code sample completely functional to my GitHub for reference

答案 1 :(得分:0)

模板化用户控件(与模板化服务器控件相对)。

这里有关于模板化用户控件的MSDN教程:http://msdn.microsoft.com/en-us/library/36574bf6(v=vs.100).aspx

如果您想要预定义的ID,那么您可以使用FindControl()方法从模板中提取控件,然后附加您需要的任何点击事件等。

e.g。

protected void Page_Init(object sender, EventArgs e)
{
  // if a message template has been defined, check for the reset button
  if(MessageTemplate != null)
  {
    // attempt to grab the reset password button
    Button btnResetPassword = MessageTemplate.FindControl("btnResetPassword ") as Button;

    // if the reset password button has been declared, attach the click event             
    if(btnResetPassword != null)
      btnResetPassword .Click += btnResetPassword_Click;  // attach click event
  }
}

protected void btnResetPassword_Click(object sender, EventArgs e)
{
  // reset password behaviour here
}

上面的代码没有完成/测试,但只是想知道我的意思。不确定这是不是你的意思?