没有找到合适的产品?
联系客服协助选型:023-68661681
提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
翻译|其它|编辑:郝浩|2007-09-27 11:17:59.000|阅读 843 次
概述:
# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>
前言
在开始写这个系列的文章之时,我想着必须深入介绍背后的原理,然后将所有需要的背景知识呈现到读者眼前,不过我现在发觉这并不是好的写作方法,要写下去对我自己来说难度也不少。最近受到 Infinities Loop 发布 TRULY Understanding Dynamic Controls (Part 4) 的刺激,我决定继续写这个系列的文章,并且领悟到了更多读者需要的是对问题的一种较为易于理解的解释,而非一种严谨的解释,因为前者更有助于读者解决当前问题并在再次遇到类似问题时自行推导解决。
其实我在本系列的第一篇文章就已经明确了怎样的文章才让读者容易接受,现在是我自己误入歧途了,所以必须纠正过来。第一篇文章的结尾建议读者自己阅读控件开发有关的书籍,之后就能完整理解和解决这个问题。实际上这是一个比较不合理的建议,大多数人并不可能花时间看完一本厚厚的控件开发书籍(ASP.NET 2.0的比 ASP.NET 1.x 的要厚了不少)。我需要做的不是复述书上的观点,那也不是我想要做的事情,真正需要做的事情是将书里面的观点浓缩为一篇文章,要让读者能解决问题的,推理看起来符合常识以至于容易接受,然而又比严密推理省下一大多文字。好吧,就让我们按照这种思路去看看如何解决一些常见的动态控件问题。
问题分类
这是受到 Infinities Loop 启发的,我们首先要将问题分类,然后逐个击破。这里的分类将最常见也最容易解决的排到上面来,然后逐步深入讨论。在开发过程中,使 ASP.NET 程序员想到要用动态控件的情景通常有如下几种:
1. 你需要呈现不确定数量的控件,但这些控件是同一类型的
2. 你需要呈现不确定类型的控件
3. 上述两个问题的综合或嵌套
4. 你需要开发自己的 Web 控件
在对问题进行分类之后,我们就容易逐个去分析解决办法了。由于分类是按照难度逐步递增的,所以这对读者来说应该是较容易理解的。
不确定数量的同类型控件
如果你要在页面上显示一个调查问卷,问卷的题目来自数据库,而任何问题都只有“是”与“否”两个选项,你决定使用 RadioButton 提供选项。这时候动态创建控件的念头应该仅仅是一闪而过的,然后你就决定使用 Repeater。
如果你在这时候没有想到 Repeater,或者任何的 TemplateControl,那么你就需要重新熟悉ASP.NET 的内置控件了。很多时候我们用多了 GridView,特别是一直都用 BoundField 的话,就很容易忘记世界上还有 TemplateField 这么一回事。
那么为什么 Repeater 在此会是一个好的选择呢?首先,连最近基本的 foreach 迭代循环它也帮我们做了,我们仅需要指定 DataSource,然后执行一下 DataBind(),它就帮我们动态为每一个数据项按照模板创建控件。其次,对于 PostBack 之后数据发生更新的情况它能应付自如。为了说明 PostBack 更新数据造成的影响,让我们再来看一个例子。
首先,我们直接在 Session 里存放一个 string[],内容为{"apple", "boy", "cat", "dog"},然后我们需要将它们显示出来,每一个项目显示为一个 LinkButton,点击之后就在数组中将它删除。我们都知道使用 Repeater 或者 GridView 搭配 ObjectDataSource 做这样简单的事情是绝对没问题的,但如果我们手动编写动态创建控件的过程呢?
按照大多数人所理解的 ASP.NET 逻辑,首先应该在 Load 这一阶段遍历数组,然后为每一个数据项创建一个 LinkButton,最后把这一切都附加到页面上唯一的那个 HtmlForm 上面去。删除怎么做呢?LinkButton 实现了 IButtonControl,所以可以添加 CommandArgument 属性,我们就把字符串保存进去好了。在 OnCommand 的时候就通过此属性识别当前需要删除的字符串,然后从数组中删除,并且还要在 HtmlForm 中搜索对应的 LinkButton 然后把它移除。
这时候你应该看看 OnLoad 中的代码是否记得为每一个控件的 ID 属性赋值,否则就会出问题了。页面一开始生成的结构应该是这样的:(左侧的是控件的 ID,右侧是控件显示的字符串)
ctl01 ("apple")
ctl02 ("boy")
ctl03 ("cat")
ctl04 ("dog")
我们点击"boy",页面进行 PostBack,然后 Load 生成同样的控件树,之后 OnDelete 删除ctl02,所以输出的控件树应该是这样的:
ctl01 ("apple")
ctl03 ("cat")
ctl04 ("dog")
我们这次点击"cat",页面又在 PostBack,但接着 Load 生成的控件树就不同了:
ctl01 ("apple")
ctl02 ("cat")
ctl03 ("dog")
必须留意到控件的 ID 属性重新编号了,然而 ASP.NET 仅仅知道我们点击了 ctl03,所以触发的 ctl03 的 OnCommand,根据现在的 ctl03 的 CommandArgument 属性,删除了"dog"字符串。这就是所谓的问题了,无指定 ID 的控件会自动按顺序分配 ID,因此 ID 具有了不确定性。
如果在 OnCommand 的时候,调用 HtmlForm 的 Controls.Clear(),是否就能移除所有控件并且让 ID 重头开始编号呢?实验结果表明上述删除过程中第一次 PostBack 后会生成这样的控件树:
ctl05 ("apple")
ctl06 ("cat")
ctl07 ("dog")
也就是说,移除确实是移除了,然而 ID 编号没有重置,而是继续编号。那么 Repeater 是怎么做到的呢?为什么直接使用 Repeater 就没有任何问题呢?这个下一篇文章再说,我们现在专心来把问题逐个击破,现在你记住这种情况选择 Repeater 或者其他更高级的数据控件就是了。
不确定类型的控件
在面对此类问题的时候,首先问问自己控件的数量,如果数量不多,直接通过设置控件的 Visible 属性解决问题就是了。这也就是说,把可能要显示的控件都声明为 Visible="false",然后在代码中判断当前应该将哪个显示出来。
如果控件比较多,然而还是能分组的,同一时间仅仅显示其中的一组,那么你应该考虑使用 MultiView,这样你的工作将会轻松不少。事实上,能够使用 MultiView 解决的,都应该优先考虑使用 MultiView 解决,这比起自己控制哪一个控件显示哪一个控件隐藏要方便多了。其实 MultiView 所做的,也就是帮你控制控件的显示与隐藏。
这样做的性能如何呢?我们关注两方面的问题,一方面是服务器端执行的资源消耗,另一方面是传输的带宽消耗。我们先来看看服务器端执行的资源消耗吧,我们最常见的消耗应该就是数据控件操作数据库时的消耗了。在 ASP.NET 1.x 时代,我们没有数据源控件,所以必须手动进行 DataBind(),这也就是说如果不手动执行 DataBind()的话就不会进行任何数据操作,因此只要我们记得在数据控件不显示的时候也不要让它执行 DataBind()就是了,那样就不会有性能损失。在 ASP.NET 2.0 当中,使用数据源控件的话数据控件是会自动 DataBind()的,这时候会造成控件隐藏时的资源消耗呢?事实上是不会的,数据控件即使已经定义了 DataSourceID 属性,它也仅仅在自己第一次可见时才进行自动 DataBind()。如果数据控件的状态是隐藏的(包括使用 MultiView 隐藏),它就不会自动进行 DataBind()。因此,在 ASP.NET 2.0 中使用数据源控件以及 MultiView 之后其底层过程还是和 ASP.NET 1.x 手动操作的一样,就是少写一些代码而已。
我们接着来看看带宽消耗如何,因为隐藏的控件不输出任何的 HTML,因此带宽消耗就是指ViewState 了。控件隐藏后,ViewState 是不变的,因此隐藏控件确实比完全不加载控件造成了更多的资源消耗,换取的是该控件的状态得以保存。一般来说,简单控件隐藏后多出来几十字节的 ViewState 是可以忽略不计的,整个页面中HTML缩进所需的空格也都几十上百字节了;但如果是复杂控件,拥有大量的 ViewState,这时候你真的应该考虑动态加载了。
总的来说,面对这类问题时首先判断显示隐藏控件的逻辑是否复杂,控件本身是否复杂。如果是比较简单的情况,则直接使用 MultiView 解决就是了。如果是复杂的情况,那就应该考虑自己使用控件将此逻辑封装在内,而不是直接在页面上暴露这些复杂性。关于封装控件的问题,在下一篇文章中再讨论,因此我们继续看下一类问题。
既不确定类型也不确定数量的控件
有时候我们面对前面两类问题都有清晰的思路,但是面对复合问题就感觉很混乱了。例如还是一个调查问卷的显示,数据来自 XML,问题类型包括单选和多选,每一道问题的选项个数也不确定,这时候怎么办呢?foreach 嵌套 foreach,外层迭代问题内层迭代选项,逐个 CheckBox/RadioButton 来生成?
这时候我们需要的是把问题分而治之逐个击破的思想。既然是上述两类问题的嵌套,我们就应该能够通过嵌套对应的解决方案来实现。对于这个调查问卷的例子,我们可以用 Repeater 来迭代问题,先把这个定下来,再考虑模板里面怎么做。模板里面需要显示的是一个不确定类型的问题,因此模板里面放一个 MutliView,把问题类型的表达式绑定到其 ActiveViewIndex 属性上,例如单选题就是0多选题就是1。然后 MultiView 里面的两个 View 各自嵌套一个 Repeater,第0个 Repeater 迭代选项并显示为 RadioButton,第1个 Repeater 迭代选项并显示为 CheckBox。就这样就完成了,我们没写任何一行后台代码,也没有动态创建任何控件。
然后我们来分析一下这个解决方案的性能。对比起动态创建控件,它所使用的控件确实是多了一倍,因为一道问题同时创建了两组选项,一组单选一组多选,只不过其中一组被隐藏了。然而隐藏掉的那一组唯一的服务器端资源消耗就是创建以及绑定,它们不输出任何的 HTML,因为它们的值不会被改变所以也不会输出任何的 ViewState,并且它们也不会触发任何事件,因此在对性能没有特别要求的情况下这样的性能损失还是可以接受的。至少,这比起你自己去研究 ASP.NET 页面生命周期然后自己写一大段代码来实现动态加载控件要好多了。
问题与实验
本系列上一篇文章的问题与实验一直没有解答,现在给出参考答案如下:
为Page增加一个ShowCheckBox的属性:
1. bool ShowCheckBox {
get { return (ViewState["ShowCheckBox"] == null) ? false : (bool)ViewState["ShowCheckBox"]; }
set { ViewState["ShowCheckBox"] = value; }
}
在 OnLoad 的时候检测 ShowCheckBox 属性,如果为 true 则添加上该 CheckBox 控件。在 Button 的 OnClick 事件中,设置 ShowCheckBox 为 true,并添加上 CheckBox。记得这两处创建的 CheckBox 必须拥有一致的 ID 属性。
2. 这是为了让 ICallbackEventHandler 的处理模型符合页面生命周期的模型。虽然 Callback 发生的时候,页面生命周期已经与 PostBack 不同,然而 ICallbackEventHandler 还是让 Callback 模仿了 PostBack 的页面生命周期。RaiseCallbackEvent 相当于 PostBack 的 Raise PostBackEvent 阶段,GetCallbackResult 相当于 PostBack 的 PreRender 阶段。前者负责事件响应,后者负责生成返回客户端的 HTML 代码。
这次想和大家讨论的问题是,你觉得你是完美主义者吗?面对上面的调查问卷需求,你会选择我所说的 Repeater 套 MultiView 再套 Repeater 的做法,从而避免写任何一行后台代码,还是会选择自己封装一个控件动态创建所有控件,避免任何不必要的性能损失?
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com
文章转载自:博客园接DevExpress原厂商通知,将于近日上调旗下产品授权价格,现在下单客户可享受优惠报价!
面对“数字中国”建设和中国制造2025战略实施的机遇期,中车信息公司紧跟时代的步伐,以“集约化、专业化、标准化、精益化、一体化、平台化”为工作目标,大力推进信息服务、工业软件等核心产品及业务的发展。在慧都3D解决方案的实施下,清软英泰建成了多模型来源的综合轻量化显示平台、实现文件不失真的百倍压缩比、针对模型中的大模型文件,在展示平台上进行流畅展示,提升工作效率,优化了使用体验。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@evget.com
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢
慧都科技 版权所有 Copyright 2003-
2025 渝ICP备12000582号-13 渝公网安备
50010702500608号