1

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

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

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

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

4

2 回答 2

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" />可选地,您的按钮可以包含一个事件处理程序,该处理程序将在事件冒泡之前进行处理。

我将此代码示例上传到我的 GitHub 以供参考

于 2012-10-02T18:33:30.627 回答
0

模板化的用户控件(与模板化的服务器控件相反)怎么样。

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

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

例如

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
}

上面的代码没有完成/测试,只是为了说明我的意思。不知道这是否是你的意思?

于 2012-10-02T10:59:15.003 回答