我正在尝试创建一个模板化复合控件,它的工作方式与 ASP.Net 的“PasswordRecovery”控件类似。
我的意思是,用户可以定义自己的模板,但是通过使用预定义的控件 ID,它定义了哪个字段,比如电子邮件地址,以及哪个按钮是发送电子邮件的按钮。
我试图查看模板化 Web 服务器控件的文档,但找不到任何关于向这些控件添加行为的内容。
或者,有没有办法完全改变 PasswordRecovery 的行为?我想发送一封带有一次性 URL 的电子邮件来更改密码,而不是该控件的常见行为。
我正在尝试创建一个模板化复合控件,它的工作方式与 ASP.Net 的“PasswordRecovery”控件类似。
我的意思是,用户可以定义自己的模板,但是通过使用预定义的控件 ID,它定义了哪个字段,比如电子邮件地址,以及哪个按钮是发送电子邮件的按钮。
我试图查看模板化 Web 服务器控件的文档,但找不到任何关于向这些控件添加行为的内容。
或者,有没有办法完全改变 PasswordRecovery 的行为?我想发送一封带有一次性 URL 的电子邮件来更改密码,而不是该控件的常见行为。
我回答了一个相关的问题:
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;
}
}
[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
此属性仅用于设计人员支持
为了正确创建子控件,您需要覆盖以下方法和属性Controls
:DataBind
和CreateChildControls
覆盖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();
}
}
<%@ 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>
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" />
可选地,您的按钮可以包含一个事件处理程序,该处理程序将在事件冒泡之前进行处理。
模板化的用户控件(与模板化的服务器控件相反)怎么样。
这里有一个关于模板化用户控件的 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
}
上面的代码没有完成/测试,只是为了说明我的意思。不知道这是否是你的意思?