转自:http://blog.zhaojie.me/2007/12/usercontrol-as-an-template.html

User Control大家肯定不会陌生,在使用ASP.NET的过程中,除了aspx页面,最常见的就莫过于ascx了。ascx是一个有独立逻辑的组件,提供了强大的复用特性,合理使用,能够大大提高开发效率。通过User Control直接生成HTML内容其实已经是一个比较常用的技巧了(尤其在AJAX时代),不过网络上这方面的内容比较少,很多人还是在苦苦地拼接字符串,因此在这里我通过一个实例简单介绍一下这个技巧。

对一个对象(文章,图片,音乐,etc.)进行评论是应用中最常见的功能之一。首先,我们定义一个Comment类,以及其中会用到的“获取”方法:

public partial class Comment{    public DateTime CreateTime { get; set; }     public string Content { get; set; }} public partial class Comment{    private static List<Comment> s_comments = new List<Comment>    {        new Comment        {            CreateTime = DateTime.Parse("2007-1-1"),            Content = "今天天气不错"        },        new Comment        {            CreateTime = DateTime.Parse("2007-1-2"),            Content = "挺风和日丽的"        },        new Comment        {            CreateTime = DateTime.Parse("2007-1-3"),            Content = "我们下午没有课"        },        new Comment        {            CreateTime = DateTime.Parse("2007-1-1"),            Content = "这的确挺爽的"        }    };     public static List<Comment> GetComments(int pageSize, int pageIndex, out int totalCount)    {        totalCount = s_comments.Count;         List<Comment> comments = new List<Comment>(pageSize);         for (int i = pageSize * (pageIndex - 1);            i < pageSize * pageIndex && i < s_comments.Count; i++)        {            comments.Add(s_comments[i]);        }         return comments;    }}

为了显示一个评论列表,我们可以使用一个用户控件(ItemComments.aspx)来封装。自然,分页也是必不可少的:

<asp:Repeater runat="server" ID="rptComments">    <ItemTemplate>        时间:<%# (Container.DataItem as Comment).CreateTime.ToString() %><br />        内容:<%# (Container.DataItem as Comment).Content %>     </ItemTemplate>    <SeparatorTemplate>        <hr />    </SeparatorTemplate>    <FooterTemplate>        <hr />    </FooterTemplate></asp:Repeater> <% if (this.PageIndex > 1)   { %>        <a href="/ViewItem.aspx?page=<%= this.PageIndex - 1 %>" title="上一页">上一页</a>&nbsp;<% } %><% if (this.PageIndex * this.PageSize < this.TotalCount)   { %>        <a href="/ViewItem.aspx?page=<%= this.PageIndex + 1 %>" title="上一页">下一页</a><% } %>

还有:

public partial class ItemComments : System.Web.UI.UserControl{    protected override void OnPreRender(EventArgs e)    {        base.OnPreRender(e);         this.rptComments.DataSource = Comment.GetComments(this.PageSize,            this.PageIndex, out this.m_totalCount);        this.DataBind();    }     public int PageIndex { get; set; }     public int PageSize { get; set; }     private int m_totalCount;    public int TotalCount    {        get        {            return this.m_totalCount;        }    }} 

然后再页面(ViewItem.aspx)中使用这个组件:

<div id="comments"><demo:ItemComments ID="itemComments" runat="server" /></div>

以及:

public partial class ViewItem : System.Web.UI.Page{    protected void Page_Load(object sender, EventArgs e)    {        this.itemComments.PageIndex = this.PageIndex;    }     protected int PageIndex    {        get        {            int result = 0;            Int32.TryParse(this.Request.QueryString["page"], out result);             return result > 0 ? result : 1;        }    }} 

打开ViewItem.aspx之后效果如下:

时间:2007/1/1 0:00:00 内容:今天天气不错


时间:2007/1/2 0:00:00 内容:挺风和日丽的


时间:2007/1/3 0:00:00 内容:我们下午没有课


下一页

这张页面的功能非常简单,那就是察看评论。当前评论的页码会使用QueryString的page项进行指定,然后在ViewItem.aspx里获取到并且设置ItemComments.ascx控件的属性。ItemComments控件会根据自身属性来获取数据,进行绑定,至于显示内容,全都定义在ascx中了。由于需要分页功能,这个评论控件中还包含了上一页和下一页的链接,他们链接的目标很简单,就是ViewItem.aspx页,并且加上页码的Query String而已。

功能是完成了,不过用着用着忽然觉得不妥,为什么呢?因为我们在翻页,或者用户发布评论的时候,整张页面都刷新了。这可不好,要知道可能ViewItem页中还有其他几个显示部分,它们可是不变的。而且如果其他几个部分也需要分页,那么可能就需要保留页面上每一部分的当前页码,这样开发的复杂性还是比较高的。

那么我们不如用AJAX吧。无论是用户察看评论时进行翻页还是发表评论,都不会对页面上的其他内容造成影响。要开发这个功能,自然需要服务器端的支持,那么该怎么做呢?一般我们总是有两种选择:

  1. 服务器端返回JSON数据,在客户端操作DOM进行呈现。
  2. 服务器端直接返回HTML内容,然后在客户端设置容器(例如上面id为comments的div)。

不过无论采用哪种做法,“呈现”的逻辑一般总是另写一遍(第一次的呈现逻辑写在了ItemComments.ascx中)。如果使用第1种做法,那么呈现逻辑就需要在客户端通过操作DOM进行呈现;如果使用第2种做法,那么就要在服务器端进行字符串拼接。无论哪种做法都违背了DRY原则,当ItemComments.ascx里的呈现方式修改时,另一处也要跟着修改。而且无论是操作DOM元素还是拼接字符串维护起来都比较麻烦,开发效率自然也就不高了。

如果我们能够直接从ItemComments控件获得HTML内容该多好啊——那么我们就这么做吧。请看如下代码(GetComments.ashx):

public class GetComments : IHttpHandler{    public void ProcessRequest(HttpContext context)    {        context.Response.ContentType = "text/plain";         ViewManager<ItemComments> viewManager = new ViewManager<ItemComments>();        ItemComments control = viewManager.LoadViewControl("~/ItemComments.ascx");         control.PageIndex = Int32.Parse(context.Request.QueryString["page"]);        control.PageSize = 3;         context.Response.Write(viewManager.RenderView(control));    }     public bool IsReusable { ... }} 

很简单的代码,不是吗?创建对象,设置属性,然后通过Response.Write输出而已。实在没什么大不了的——不过关键就在于ViewManager类,我们来看一下它是怎么实现的:

public class ViewManager<T> where T : UserControl{    private Page m_pageHolder;     public T LoadViewControl(string path)    {        this.m_pageHolder = new Page();        return (T)this.m_pageHolder.LoadControl(path);    }     public string RenderView(T control)    {        StringWriter output = new StringWriter();         this.m_pageHolder.Controls.Add(control);        HttpContext.Current.Server.Execute(this.m_pageHolder, output, false);         return output.ToString();    }}

ViewManager中只有两个方法:LoadViewControl和RenderView。LoadViewControl方法的作用是创建一个Control实例并返回,RenderView方法的作用则就是生成HTML了。这个实现方式的技巧在于使用了一个新建的Page对象作为生成控件的“容器”,而最后其实我们是将Page对象的整个生命周期运行一遍,并且将结果输出。由于这个空的Page对象不会产生任何其他代码,因此我们得到的,就是用户控件生成的代码了。

不过要实现这个AJAX效果,还需要做两件事情。

第一,就是简单修改一下ItemComments控件中的翻页链接,让它被点击时调用一个JavaScript函数。例如“上一页”的代码就会变成:

<a href="/ViewItem.aspx?page=<%= this.PageIndex - 1 %>" title="上一页"    onclick="return getComments(<%= this.PageIndex - 1 %>);">上一页</a>

第二,就是实现getComments这个客户端方法。在这里我使用了prototype框架,好处就是能够用相当简洁的代码来做到替换HTML的AJAX效果:

<script type="text/javascript" language="javascript">    function getComments(pageIndex)    {        new Ajax.Updater(            "comments",            "/GetComments.ashx?page=" + pageIndex + "&t=" + new Date(),            { method: "get" });                 return false; // IE only    }</script>

大功告成。

其实就像之前所说的那样,使用UserControl进行HTML代码生成是一个十分常用的技巧。尤其在AJAX应用越来越普及的情况下,合理使用上面提到的方式可以方便的为我们的应用添加AJAX效果。而且很多情况下,我们即使不需要在页面上显示内容,也可以将内容使用UserControl进行编辑。因为编写UserControl比拼接字符串的方式无论是在开发效率上还是可维护性上都高出许多。由于这个方式其实使用了WebForms这个久经考验的模型,因此在执行效率方面也是相当高的。此外,就刚才的例子来说,使用UserCotrol进行HTML生成还有其他好处:

  1. 页面呈现逻辑只实现了一次,提高了可维护性。
  2. 不会影响页面的SEO,因为在客户端<a />的href还是有效的。

事实上,WebForms是一个非常强大的模型,所以ASP.NET MVC的View也使用了WebForms的引擎。通过上面这个例子,我们其实还可以做到其他很多东西——例如用UserControl来生成XML数据,因为UserControl本身不会带来任何额外的内容。

转载于:https://www.cnblogs.com/yuewh491/archive/2010/11/03/1867997.html

技巧:使用User Control做HTML生成(转)相关推荐

  1. 技巧:使用User Control做HTML生成

    User Control大家肯定不会陌生,在使用ASP.NET的过程中,除了aspx页面,最常见的就莫过于ascx了.ascx是一个有独立逻辑的组件,提供了强大的复用特性,合理使用,能够大大提高开发效 ...

  2. python 根据判断产生新列_pandas DataFrame 根据多列的值做判断,生成新的列值实例...

    环境:Python3.6.4 + pandas 0.22 主要是DataFrame.apply函数的应用,如果设置axis参数为1则每次函数每次会取出DataFrame的一行来做处理,如果axis为1 ...

  3. 简历中的项目如何体现实战能力? 如何有技巧地描述你做过的 project?

    专栏 | 九章算法 网址 | http://www.jiuzhang.com Side Project,指的是工作.学习之余的小项目.副项目.将 side project 写到你的简历中,可以为你带来 ...

  4. excel 两组数据交点_让科研人相见恨晚的技巧,用Excel做柱状图、箱型图及数据分析!(转载自ZSCI)...

    来源:ZSCI 让科研人相见恨晚的技巧,用Excel做柱状图.箱型图及数据分析! 面对大量的实验数据,却不知道如何快速的将自己想要的结果筛选出来.筛选后也只能做简单的数据图,绘制高级的图形又成了一个难 ...

  5. [转]网店博客营销之微博实战技巧:还没有做微博的掌柜看过来

    网店博客营销之微博实战技巧:还没有做微博的掌柜看过来 提起微博,估计对于很多掌柜来说还是新鲜事.因为很多掌柜对于传统的博客都不太感冒,还未深究,现在又来了一个微博.其实,2009年中国的网络才正式步入 ...

  6. 用时间做种子生成随机数

     [转] 用时间做种子生成随机数 分类: VC++ 2011-06-26 19:11 2768人阅读 评论(0) 收藏 举报 null测试 我们知道rand()函数可以生成随机数,其实是在种子的基 ...

  7. 短视频剪辑技巧分享,先做排序不能忘,观看效果会更佳

    短视频剪辑技巧分享,先做排序不能忘,观看效果会更佳 短视频剪辑学起来其实还是很简单的,只是如果想要成为剪辑大神,还是需要时间的磨炼,多多的剪辑作品,进行练习,并查扣补缺,了解一些短视频剪辑的小技巧,才 ...

  8. 亚马逊选品有哪些技巧?如何才能做出爆款产品?

    在亚马逊开店的卖家想必都会面临同样的问题:如何选品才能增加店铺销量?有点经验的卖家都知道,在选品上,盲目跟风只能在大卖后面争夺一点被压缩到极限的市场份额.只有符合市场需求.符合店铺定位的选品,才能在跨 ...

  9. mastercam后处理升级_MasterCam软件后处理技巧大揭秘,做数控编程的都收藏了

    mastercam软件后处理技巧mastercam软件是一款很优秀的cam软件,市场占有率很高.也是数控加工首先的计算机自动生成程序的软件.很重要的一点是,它的后处理是开放式的. 下面就谈谈它的后处理 ...

  10. flowmap怎么做_Photoshop生成的流动贴图(flowmap)

    Photoshop提供了大量工具以供贴图编辑和图像控制. 很方便的一点是,您也可以使用这些工具来生成流动贴图(flowmap). 本篇文章将为您展示如何使用UV贴图和Epic提供的操作在Photosh ...

最新文章

  1. 【SICP练习】136 练习3.67
  2. android -各种适配器
  3. T-SQL IN 谓词
  4. 最大调用堆栈大小超出错误
  5. wxWidgets:wxMenuItem类用法
  6. 取后端数据_用 Flask+Axios 实现前后端数据通信:查询动森鱼类价格
  7. HAProxy + Keepalived + Flume 构建高性能高可用分布式日志系统
  8. 截止到2013年,核心Java帖子
  9. “宇宙总统”计票(洛谷P1781题题解,Java语言描述)
  10. mysql 查询最早 表,【MySQL】MySQL查询表的创建时间
  11. 关于Android 的内存泄露及分析
  12. JavaScript 取得当前页面的URL网址参数
  13. 【RBM】代码学习--DeepLearningToolBox
  14. 12-8下午 php语法
  15. 酒桌上的潜规则和技巧,男人必学
  16. 加密狗登录PHP开发,C# 使用加密狗登录 示例源码
  17. 微信html 全屏显示,关于微信上网页图片点击全屏放大效果
  18. 手把手教你用java发送邮件
  19. 日本风俗业数据_神奇宝贝如何融入日本民俗
  20. 美国音乐学院计算机音乐专业排名2015年,美国音乐学院排名小提琴专业排名大全(本科)...

热门文章

  1. appium python很慢_appium+python自动化测试遇到的坑及处理方案
  2. ATF(ARM Trusted firmware)完成启动流程
  3. 使用pjsip传输已经编码的视频,源码在github
  4. 使用Arcpy进行数据批处理-批量裁剪
  5. a deep leaning
  6. 树算法系列之四:XGBoost
  7. 你应该知道的RPC原理
  8. hive 窗口函数 应用场景与实战详解
  9. shell判断字符串为空
  10. VS2012错误之 warning LNK4075: 忽略“/EDITANDCONTINUE”(由于“/SAFESEH”规范)