我正在尝试创建一个模板化复合控件,它的工作方式与ASP.Net的“PasswordRecovery”控件类似。
由此,我的意思是用户可以定义自己的模板,但是,通过使用预定义的控件ID,它定义哪个字段,比如电子邮件地址,以及哪个按钮是发送e-邮件。
我试图查看模板化Web服务器控件的文档,但我找不到任何关于向这些控件添加行为的内容。
或者,有没有办法完全改变PasswordRecovery的行为?我想发送一封带有一次性URL的电子邮件来更改密码而不是该控件的常见行为。
答案 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;
}
}
[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" />
可选,您的按钮可以包含在冒泡事件之前处理的事件处理程序。
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
}
上面的代码没有完成/测试,但只是想知道我的意思。不确定这是不是你的意思?