2013-05-04 36 views
0

我已經創建了一些從文本框繼承的自定義文本框。 對於下一步我想用包裝器註冊JavaScript。使用裝飾模式爲asp.net控件

裝飾模式允許我做,如果我只能從文本框繼承它並將自定義文本框作爲構造函數參數傳遞。

問題是,當我向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是一個具體的IMPL。 IField的忽略...):

public class ValidationEmail : ValidationBase 
{ 
    public ValidationEmail() 
     : base(new EmailField(string.Empty)) 
    { 
    } 
} 

最後,我想實現這個(我已經打定了主意在寫字板,這不可能是精確的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"/> 
+0

您能否詳細說明您的特殊情況?你想用Decorator模式實現控制,你試圖做什麼或嘗試什麼? – 2013-05-05 10:03:05

+0

@AlexanderManekovskiy感謝您的評論。我已經更新了我的問題。 – pilavust 2013-05-05 22:39:35

回答

1

我解決我的問題AlexanderManekovskiy的幫助,還有一些其他問題:

,這裏是解決方案:

我已將JsRegistererForValidationBase設爲WebControl並實施了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

詳細imlementation
1

我不認爲Decorator模式擬合在這裏。一般來說,我看到了更多的Builder和Factory Method for ASP.NET控件的應用程序。

要部分解決您的任務,您可以使用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的值爲blog post,但重寫控件的構造函數並簡化解決方案並不是一件容易的事情。

作爲替代方案,將工作,我可以建議增加一個抽象(或虛擬的)方法類似RegisterScriptsValidationBase並調用它OnPreRender。每個控件都會知道它需要什麼腳本,並且新的驗證器控件創建過程將會乾淨而簡單。如果你想從具體實現中分離JS腳本的知識,那麼就可以使用ASP.NET動態數據(參見MetaTable)中所述的方法。

我能看到的另一件事是,你的想法已經足夠接近DynamicControl,也許有可能從ASP.NET DynamicData中獲得更多的想法,如Field TemplatesIFielTemplateFactory

+0

如何創建'WebControl'繼承了'INamingContainer'?作爲孩子,它只接受'ValidationBase'和OnLoad它註冊javascriptes。 – pilavust 2013-05-07 20:59:10

+0

@pilavu​​st聽起來不錯,如果它適合你的情況。另一個想法是,您可以創建一個「每頁一個/主」一個「ValidationScriptManager」(如'ScriptManager')控件,其中驗證控件將被註冊,並在請求期間收集,合併和返回必需的腳本。 – 2013-05-08 15:26:48

+0

我同意你的意見。我非常感謝你的支持。爲了提出這個問題,我可以用我的解決方案/實施方案回答這個問題嗎? – pilavust 2013-05-08 17:22:29