C# 对asp.net控件使用装饰器模式
我已经创建了一些从textbox继承的自定义textbox。 下一步,我想用包装器注册javascript 装饰器模式允许我这样做,只要我可以从textbox继承它并将自定义textbox作为构造函数参数传递 问题是,当我向aspx页面添加控件时,如何使用构造函数,或者基本上如何为asp.net控件使用装饰器模式 编辑: 这就是我的验证基类(IField是一个验证接口,可以忽略): 这是我的具体类(EmailField是IField ignore…)的具体实现: 最后我想实现这一点(我已经在写字板上下定决心,这不可能是精确的实现): 问题是我如何使用这个装饰器?由于asp.net构造自动控制:C# 对asp.net控件使用装饰器模式,c#,asp.net,user-controls,decorator,C#,Asp.net,User Controls,Decorator,我已经创建了一些从textbox继承的自定义textbox。 下一步,我想用包装器注册javascript 装饰器模式允许我这样做,只要我可以从textbox继承它并将自定义textbox作为构造函数参数传递 问题是,当我向aspx页面添加控件时,如何使用构造函数,或者基本上如何为asp.net控件使用装饰器模式 编辑: 这就是我的验证基类(IField是一个验证接口,可以忽略): 这是我的具体类(EmailField是IField ignore…)的具体实现: 最后我想实现这一点(我已经在写字
<vc:ValidationEmail ID="ValidationEmail1" runat="server"/>
我不知道我可以使用这个(我可以把构造函数参数放在哪里?)
我认为Decorator模式不适合这里。总的来说,我看到了更多用于ASP.NET控件的Builder和Factory方法的应用程序 要部分解决您的任务,您可以使用。它将使您能够将控件的类型从
ValidationBase
更改为JsRegisterDecorator
或validationmail
。您需要使用ControlBuilderAttribute
装饰ValidationBase
类,从ControlBuilder
继承生成器类并重写Init
方法
[ControlBuilder(typeof(ValidationBaseBuilder))]
public abstract class ValidationBase : TextBox, IField { }
public class ValidationBaseBuilder: ControlBuilder
{
public override void Init(TemplateParser parser, ControlBuilder parentBuilder, Type type, string tagName, string id, System.Collections.IDictionary attribs)
{
var newType = typeof(/*here you can put a JsRegisterDecorator type*/);
base.Init(parser, parentBuilder, t, tagName, id, attribs);
}
}
但我不确定这种方法。ControlBuilder无法让您轻松控制构造函数。当然,您可以在ControlBuilder中重写,David Ebbo有一本值得一读的书,但重写控件的构造函数并使解决方案变得简单并不是一件容易的事情
作为替代方案,我可以建议在ValidationBase
中添加一个抽象(或虚拟)方法,如RegisterScripts
,并在OnPreRender
中调用它。每个控件都知道它需要什么脚本,新的验证程序控件的创建过程将是干净而简单的。如果您想将JS脚本的知识与具体实现分开,那么可以使用ASP.NET DynamicData(read)中所示的方法
我可以看到的另一件事是,您的想法与ASP.NET DynamicData非常接近,并且可能会从中获得更多想法,例如,
IFielTemplateFactory
我在AlexanderManekovskiy的帮助下解决了我的问题,还有一些其他问题:
JsRegistererForValidationBase
作为WebControl
,并在mingContaier中实现了
对于我创建的子元素children
属性,该属性接受验证基础的olny列表
最后,我注册了js
代码如下:
[ParseChildren(true)]
[PersistChildren(true)]
[ToolboxData(@"<{0}:JsRegistererForVB runat=""server""></{0}:JsRegistererForVB>")]
public class JsRegistererForValidationBase : WebControl, INamingContainer
{
private ValidationFieldCollection _children;
[PersistenceMode(PersistenceMode.InnerProperty)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ValidationFieldCollection Children
{
get
{
if (_children == null)
_children = new ValidationFieldCollection();
return _children;
}
}
protected override void CreateChildControls()
{
Controls.Clear();
foreach (var c in _children)
Controls.Add(c);
}
protected override void OnInit(EventArgs e)
{
//DO THE REGISTER STUFF
base.OnInit(e);
}
protected override void Render(HtmlTextWriter writer)
{
RenderChildren(writer);
}
}
public class ValidationFieldCollection : List<ValidationBase> { }
[ParseChildren(true)]
[儿童(对)]
[ToolboxData(@“”)]
公共类JsRegistererForValidationBase:WebControl,INamingContainer
{
private ValidationFieldCollection_子项;
[PersistenceMode(PersistenceMode.InnerProperty)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
公共验证字段集合子项
{
得到
{
if(_children==null)
_children=新的ValidationFieldCollection();
返回儿童;
}
}
受保护的覆盖无效CreateChildControls()
{
控件。清除();
foreach(变量c在子对象中)
添加(c);
}
受保护的覆盖无效OnInit(事件参数e)
{
//做登记工作
碱基.奥尼特(e);
}
受保护的覆盖无效渲染(HtmlTextWriter编写器)
{
伦德尔德伦(作家);
}
}
公共类ValidationFieldCollection:列表{}
}
在aspx端,它变成这样:
<vc:JsRegisterer ID="JsRegisterer1" runat="server">
<Children>
<vc:ValidationEmail ID="ValidationEmail1" runat="server"/>
<vc:ValidationEmail ID="ValidationEmail2" runat="server"/>,
<!--etc-->
</Children>
</vc:JsRegisterer>
,
对于详细的实施,我将代码添加到了中,您能否详细说明您的特定场景?将装饰图案应用于控件时,您希望实现什么,您尝试过做什么或尝试过什么?@AlexanderManekovskiy感谢您的评论。我已经更新了我的问题。如何创建WebControl
inheritatedINamingContainer
?作为孩子,它只接受ValidationBase
,并且只加载它register javascripts。@如果适合你的情况,pilavust听起来不错。另一个想法是,您可以创建一个“每页一个/master”ValidationScriptManager
(如ScriptManager
)控件,在该控件中注册验证控件,并在请求期间收集、合并和返回必要的脚本。我同意您的看法。我非常感谢你的支持。为了回答这个问题,我可以用我的解决方案/实施方案来回答吗?@Pilav当然可以。看看你是如何解决这个问题的会很有趣。
<vc:JsRegisterDecorator ID="ValidationEmailWithJs1" runat="server"/>
[ControlBuilder(typeof(ValidationBaseBuilder))]
public abstract class ValidationBase : TextBox, IField { }
public class ValidationBaseBuilder: ControlBuilder
{
public override void Init(TemplateParser parser, ControlBuilder parentBuilder, Type type, string tagName, string id, System.Collections.IDictionary attribs)
{
var newType = typeof(/*here you can put a JsRegisterDecorator type*/);
base.Init(parser, parentBuilder, t, tagName, id, attribs);
}
}
[ParseChildren(true)]
[PersistChildren(true)]
[ToolboxData(@"<{0}:JsRegistererForVB runat=""server""></{0}:JsRegistererForVB>")]
public class JsRegistererForValidationBase : WebControl, INamingContainer
{
private ValidationFieldCollection _children;
[PersistenceMode(PersistenceMode.InnerProperty)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ValidationFieldCollection Children
{
get
{
if (_children == null)
_children = new ValidationFieldCollection();
return _children;
}
}
protected override void CreateChildControls()
{
Controls.Clear();
foreach (var c in _children)
Controls.Add(c);
}
protected override void OnInit(EventArgs e)
{
//DO THE REGISTER STUFF
base.OnInit(e);
}
protected override void Render(HtmlTextWriter writer)
{
RenderChildren(writer);
}
}
public class ValidationFieldCollection : List<ValidationBase> { }
<vc:JsRegisterer ID="JsRegisterer1" runat="server">
<Children>
<vc:ValidationEmail ID="ValidationEmail1" runat="server"/>
<vc:ValidationEmail ID="ValidationEmail2" runat="server"/>,
<!--etc-->
</Children>
</vc:JsRegisterer>