[英]Use Decorator Pattern for asp.net controls
我创建了一些从文本框继承的自定义文本框。 对于下一步,我想用包装器注册javascript。
装饰器模式允许我这样做,只要我可以从文本框继承它并传递自定义文本框作为构造函数参数。
问题是我在向aspx页面添加控件时如何使用构造函数,或者基本上如何在asp.net控件中使用装饰器模式。
编辑:
这只是我的验证基类(IField是一个验证接口。可以忽略它):
public abstract class ValidationBase : TextBox, IField
{
private readonly IField _field;
protected ValidationBase(IField field)
{
_field = field;
}
public int MinLength
{
get { return _field.MinLength; }
set { _field.MinLength = value; }
}
public bool Required
{
get { return _field.Required; }
set { _field.Required = value; }
}
// other porperties etc...
protected override void OnPreRender(EventArgs e)
{
// DO SOME STUFF...
base.OnPreRender(e);
}
}
这是我的具体课程(EmailField是IField忽略的具体内容......):
public class ValidationEmail : ValidationBase
{
public ValidationEmail()
: base(new EmailField(string.Empty))
{
}
}
最后我想实现这个(我已经在wordpad上下定决心,这不是确切的impl。):
public class JsRegisterDecorator : ValidationBase
{
private readonly ValidationBase _validationObj;
//I am not quite sure about the constructor but i can handle
public JsRegisterDecorator(ValidationBase concreteValidationObj)
: base(concreteValidationObj)
{
_validationObj = concreteValidationObj;
}
//Wrap the properties
protected override void OnPreRender(EventArgs e)
{
//Register JS Files...
_validationObj.OnPreRender(e);
}
}
问题是我怎么能用这个装饰器? 因为asp.net构造控件自动:
<vc:ValidationEmail ID="ValidationEmail1" runat="server"/>
我不知道我可以使用它(我可以在哪里放置构造函数参数?):
<vc:JsRegisterDecorator ID="ValidationEmailWithJs1" runat="server"/>
我认为Decorator模式不适合这里。 总的来说,我看到了更多针对ASP.NET控件的Builder和Factory Method的应用程序。
要部分解决您的任务,您可以使用ControlBuilder 。 它将使您能够将控件的类型从ValidationBase
更改为JsRegisterDecorator
或ValidationEmail
。 您需要使用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中覆盖ProcessGeneratedCode ,而David Ebbo有一篇值得一读的博客文章,但重写构造函数进行控制并简化解决方案并不是一件容易的事。
作为替代方案,我可以建议在ValidationBase
添加一个抽象(或虚拟)方法,如RegisterScripts
,并在OnPreRender
调用它。 每个控件都会知道它需要哪些脚本,并且新验证器控件创建的过程将是简洁的。 如果您想将JS脚本的知识与具体实现分开,那么可以使用ASP.NET DynamicData(read MetaTable )中的方法。
我能看到的另一件事是你的想法足够接近DynamicControl ,也许有可能从ASP.NET DynamicData获得更多的想法,比如Field Templates和IFielTemplateFactory
。
我解决了我的问题AlexanderManekovskiy的帮助以及其他一些问题:
这是解决方案:
我已将JsRegistererForValidationBase
作为WebControl
并实现了INamingContaier
。
对于children元素,我创建了Children
属性,它接受了Validation Base
olny列表。
最后是OnInit
方法,我已经注册了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> { }
}
在aspx方面它变成这样:
<vc:JsRegisterer ID="JsRegisterer1" runat="server">
<Children>
<vc:ValidationEmail ID="ValidationEmail1" runat="server"/>
<vc:ValidationEmail ID="ValidationEmail2" runat="server"/>,
<!--etc-->
</Children>
</vc:JsRegisterer>
对于详细的实现,我将代码添加到codeplex中
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.