ASP.NET 自定义控件 - 复合材料
-
09-06-2019 - |
题
概括
大家好,
好的,进一步了解我的自定义控件冒险之旅......
综上所述,这里是我了解了自定义控件的三个主要“类”。如果本文有任何错误,请随时纠正我!
- 用户控件 - 继承自 用户控制 并包含在一个 ASCX 文件。它们的功能非常有限,但它们是在设计师支持下获得一些 UI 通用性的快速而轻松的方法。
- 自定义复合控件 - 这些是继承自的控件 网页控制 您可以将预先存在的控件添加到 创建子控件 方法。这提供了极大的灵活性,但缺乏设计人员支持而无需额外编码。但它们具有高度可移植性,因为它们可以编译成 DLL。
- 自定义渲染控件 - 与自定义复合控件类似,它们被添加到 Web 控件库项目中。控件的呈现完全由程序员通过重写来控制 使成为 方法。
我的想法..
好的,在使用自定义复合材料时,我发现了以下内容:
- 您几乎无法控制 HTML 输出,因此很难“调试”。
- 这 创建子控件 (以及后续方法)可能会变得非常忙碌 控件.添加(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<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);
}
罗布,你是对的。我提到的方法是一种混合方法。使用 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(@"<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;
};
当您拥有大型 Web 应用程序并希望在许多地方重用大块时,使用自定义复合控件是有道理的。然后,您只需添加您正在开发的子控件,而不必重复自己。在我最近工作的一个大型项目中,我们所做的如下:
- 每个复合控件都有一个容器。用作控件内所有内容的包装。
- 每个复合控件都有一个模板。一个 ascx 文件(不带 <%Control%> 指令),仅包含模板的标记。
- 容器(本身就是一个控件)是从模板初始化的。
- 该容器公开模板中所有其他控件的属性。
- 您仅在复合控件中使用 this.Controls.Add([the_container]) 。
事实上,您需要一个基类来负责使用指定模板初始化容器,并在模板中找不到控件时引发异常。当然,这对于小型应用程序来说可能有点过分了。如果您没有重用代码和标记并且只想编写简单的控件,那么最好使用用户控件。
您也许可以利用此技术来简化设计时:
http://aspadvice.com/blogs/ssmith/archive/2007/10/19/Render-User-Control-as-String-Template.aspx
基本上,您可以使用 LoadControl 方法在运行时创建用户控件的实例,然后将其传递给某种状态包,然后将其附加到控件树。因此,您的复合控件实际上更像是一个控制器,而 .ascx 文件就像一个视图。
这将为您省去实例化整个控件树并在 C# 中设置控件样式的麻烦!