ASP.NET自定义控件 – 复合材料

摘要

大家好,
好的,进一步进入我的自定义控件冒险……

总之,这是我已经了解了自定义控件的三个主要“类”。 如果有任何错误,请随时纠正我!

  1. UserControls – inheritance自UserControl并包含在ASCX文件中。 这些内容在他们能做的事情上非常有限,但是通过设计师支持获得一些UI通用性是一种快速而轻松的方式。
  2. 自定义复合控件 – 这些是从WebControlinheritance的控件,您可以在CreateChildControls方法中向控件添加预先存在的控件。 这提供了极大的灵活性,但缺乏设计师支持而无需额外编码。 它们是高度可移植的,因为它们可以编译成DLL。
  3. 自定义渲染控件 – 与自定义复合控件类似,这些控件将添加到Web控件库项目中。 控制器的渲染完全由程序员通过重写Render方法来控制。

我的想法..

好的,所以在玩自定义复合材料时,我发现了以下内容:

  • 您很少/无法控制HTML输出,因此难以“调试”。
  • CreateChildControls (和后续方法)可以在任何地方真正忙于Controls.Add(myControl)
  • 我发现渲染表(无论是布局还是内容)都非常尴尬。

问题..

所以,我承认,我是新手,所以我可能会偏离上面提到的一些观点。

  • 你使用复合材料吗?
  • 你有任何巧妙的技巧来控制HTML输出吗?
  • 你只是说“用它来下地狱”并继续创建自定义渲染控件吗?

因为我知道有多少好的控制开发可以缩短整体开发时间,所以我很想在脑子里真正坚定。

我期待你的回答^ _ ^

我说继续使用自定义渲染控件。 我发现在大多数情况下,复合可以更容易地完成并在UserControl中使用,但除此之外的任何东西,你需要有一个更好的控制程度(双关语),值得你自己的渲染策略。

可能有一些控件非常简单,值得一个复合(例如,一个文本框与基于javascript / dhtml的日期选择器相结合),但除了这个例子之外,它看起来像是自定义渲染控件。

这是我用于自定义渲染的另一种扩展方法:

public static void WriteControls (this HtmlTextWriter o, string format, params object[] args) { const string delimiter = "<2E01A260-BD39-47d0-8C5E-0DF814FDF9DC>"; var controls = new Dictionary(); for(int i =0; i < args.Length; ++i) { var c = args[i] as Control; if (c==null) continue; var guid = Guid.NewGuid().ToString(); controls[guid] = c; args[i] = delimiter+guid+delimiter; } var _strings = string.Format(format, args) .Split(new string[]{delimiter}, StringSplitOptions.None); foreach(var s in _strings) { if (controls.ContainsKey(s)) controls[s].RenderControl(o); else o.Write(s); } } 

然后,要在RenderContents()方法中呈现自定义合成,我写这个:

 protected override void RenderContents(HtmlTextWriter o) { o.WriteControls (@"
{0} {1}
" ,Text ,control1); }

罗布,你是对的。 我提到的方法是一种混合方式。 拥有ascx文件的优势在于,在我看过的每个项目中,设计师都会感觉最适合编辑实际标记,而使用ascx,设计师可以单独工作。 如果您以后不打算对控件本身进行实际的CSS /标记/设计更改,则可以使用自定义呈现控件。 正如我所说,我的方法只适用于更复杂的场景(这些可能是你需要设计师的地方:))

我经常使用复合控件。 而不是重写Render或RenderContents,只需为每个Control分配一个CssClass并使用样式表。 对于多个Controls.Add,我使用扩展方法:

 //Controls.Add(c1, c2, c3) static void Add(this ControlCollection coll, params Control[] controls) { foreach(Control control in controls) coll.Add(control); } 

对于快速和脏的渲染,我使用这样的东西:

 writer.Render(@"
{0}
", Text); control1.RenderControl(writer); writer.Render("
");

为了初始化控件属性,我使用属性初始化器语法:

 childControl = new Control { ID="Foo" , CssClass="class1" , CausesValidation=true; }; 

使用自定义复合控件时,您需要拥有大型Web应用程序并希望在许多地方重用大块。 然后你只会添加你正在开发的子控件,而不是重复自己。 在我最近工作的一个大型项目中,我们所做的是以下内容:

  • 每个复合控件都有一个容器。 用作控件内部所有内容的包装。
  • 每个复合控件都有一个模板。 一个ascx文件(没有<%Control%>指令),只包含模板的标记。
  • 容器(作为控件本身)从模板初始化。
  • 容器公开模板中所有其他控件的属性。
  • 您只在复合控件中使用this.Controls.Add([the_container])。

实际上,您需要一个基类来处理使用指定模板初始化容器,并在模板中找不到控件时抛出exception。 当然,这可能是一个小型应用程序的过度杀伤力。 如果您没有重用的代码和标记,并且只想编写简单的控件,那么最好使用用户控件。

您可以使用此技术使设计时更容易:

http://aspadvice.com/blogs/ssmith/archive/2007/10/19/Render-User-Control-as-String-Template.aspx

基本上,您使用LoadControl方法在运行时创建用户控件的实例,然后将其交给某种状态包,然后将其附加到控制树。 因此,您的复合控件实际上会像更多的控制器一样运行,而.ascx文件就像一个视图。

这样可以省去必须实例化整个控制树并在C#中设置控件样式的麻烦!