0

我创建了一些从文本框继承的自定义文本框。对于下一步,我想用包装器注册 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))
    {
    }
}

最后我想实现这个(我已经在写字板上下定了决心,这不能是确切的实现。):

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"/>
4

2 回答 2

1

我解决了我的问题 AlexanderManekovskiy 的帮助以及其他一些问题:

这是解决方案:

我已经制作JsRegistererForValidationBaseWebControl实施了INamingContaier.

对于子元素,我创建了Children接受 .olny 列表的属性Validation Base

最后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

于 2013-05-10T18:24:55.753 回答
1

我认为 Decorator 模式在这里不太合适。总的来说,我看到了更多用于 ASP.NET 控件的 Builder 和 Factory Method 应用程序。

要部分解决您的任务,您可以使用ControlBuilder。它将使您能够将控件的类型从 更改ValidationBaseJsRegisterDecoratorValidationEmail。您需要用 装饰ValidationBaseControlBuilderAttribute,继承构建器类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 有一篇文值得一读,但重写构造函数以进行控制并简化解决方案并不是一件容易的事。

作为替代方案,我可以建议添加一个抽象(或虚拟)方法,如RegisterScriptsinsideValidationBase并在OnPreRender. 每个控件都将知道它需要什么脚本,并且新验证器控件的创建过程将简洁明了。如果您想将 JS 脚本的知识与具体实现分开,则可以使用 ASP.NET DynamicData(读取MetaTable)中所见的方法。

我可以看到的另一件事是,您的想法与DynamicControl足够接近,也许可以从 ASP.NET DynamicData 中获得更多想法,例如字段模板IFielTemplateFactory.

于 2013-05-06T15:20:56.890 回答