19

概括

大家好,
好的,通过自定义控件进一步探索我的冒险......

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

  1. UserControls - 从UserControl继承并包含在ASCX文件中。它们的功能非常有限,但是通过设计器支持获得一些 UI 通用性是一种快速而轻松的方法。
  2. 自定义复合控件- 这些是从WebControl继承的控件,您可以在其中将预先存在的控件添加到CreateChildControls方法中的控件。这提供了极大的灵活性,但在没有额外编码的情况下缺乏设计者支持。它们是高度可移植的,因为它们可以编译成 DLL。
  3. 自定义呈现控件- 与自定义复合控件类似,这些控件被添加到 Web 控件库项目中。控件的呈现完全由程序员通过重写Render方法来控制。

我的想法..

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

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

问题..

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

  • 您使用复合材料吗?
  • 你有什么巧妙的技巧来控制 HTML 输出吗?
  • 你只是说“见鬼去吧”然后继续创建一个自定义呈现的控件吗?

因为我知道良好的控制开发可以在多大程度上缩短整体开发时间,所以我很想牢记这一点。

期待你的回答^_^

4

6 回答 6

5

我说继续使用自定义呈现的控件。我发现在大多数情况下,复合可以更容易地在 UserControl 中完成和使用,但除此之外,您需要有更精细的控制(双关语意外)以实现您自己的渲染策略。

可能有足够简单的控件值得组合(例如,文本框与基于 javascript/dhtml 的日期选择器相结合),但除此之外,看起来自定义呈现的控件是要走的路。

于 2008-08-20T07:53:32.230 回答
3

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

 public static void WriteControls
        (this HtmlTextWriter o, string format, params object[] args)
 { 
    const string delimiter = "<2E01A260-BD39-47d0-8C5E-0DF814FDF9DC>";
    var controls  = new Dictionary<string,Control>();

    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
         (@"<table>
               <tr>
                    <td>{0}</td>
                    <td>{1}</td>
               </tr>
             </table>"
            ,Text
            ,control1);
 }
于 2008-08-20T13:18:31.417 回答
2

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

于 2008-08-20T19:44:35.810 回答
1

我经常使用复合控件。无需覆盖 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(@"<table>
                   <tr><td>{0}</td></tr>
                   <tr>
                       <td>", Text);
control1.RenderControl(writer);
writer.Render("</td></tr></table>");

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

childControl = new Control {  ID="Foo"
                            , CssClass="class1"
                            , CausesValidation=true;
                           };
于 2008-08-20T07:56:49.007 回答
1

在您有一个大型 Web 应用程序并希望在许多地方重用大块的情况下,使用自定义复合控件是有好处的。然后,您将只添加您正在开发的子控件,而不是重复自己。在我最近工作的一个大型项目中,我们所做的如下:

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

实际上,您需要一个基类来负责使用指定模板初始化容器,并在模板中找不到控件时抛出异常。当然,在小型应用程序中这可能是一种矫枉过正的做法。如果您没有重用代码和标记并且只想编写简单的控件,则最好使用用户控件。

于 2008-08-20T10:27:56.663 回答
0

您也许可以利用这种技术来简化设计时:

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

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

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

于 2008-09-16T11:20:20.213 回答