繁体   English   中英

对于asp.net控件使用Decorator Pattern

[英]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更改为JsRegisterDecoratorValidationEmail 您需要使用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 TemplatesIFielTemplateFactory

我解决了我的问题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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM