FineUIPro控件库

FineUIPro是一套基于jQuery的专业ASP.NET控件库,始于2008年的开源版FineUI控件库。

当年为了提升项目的开发效率,降低代码复杂度,减少对CSS和JavaScript的依赖,我们提出了"No JavaScript, No CSS, No UpdatePanel,No ViewState,No WebServices"的口号,现在看起来仍然激动人心。

首先,JavaScript灵活性与复杂性使得大型项目的开发备受挑战,FineUIPro尝试使用服务器端的强类型语言(C#,VB.NET)来代替大部分的JavaScript实现,不仅可以利用IDE的强大功能(智能提示,代码重构),而且强类型语言的编译时错误检查也是一个加分项。

其次,FineUIPro提供统一的控件集合和页面主题,使得我们无需在代码中自定义CSS样式,不仅减少编码和调试CSS的工作量,而且能够保持整个项目中页面风格的统一和美观。

最后,FineUIPro内置了AJAX的交互支持,使得我们无需写一行JavaScript代码,就能把整个页面的回发变为AJAX过程。另外,FineUIPro也内置了IFrame支持,有助于在页面层级对代码进行解耦合。

那么,FineUIPro是如何工作的呢?FineUIPro的控件使用和原生的ASP.NET控件有哪些异同点?FineUIPro的AJAX交互过程又是什么样子的呢?

为了回答这些问题,我们将分别使用FineUIPro和ASP.NET控件来实现一个服务器端分页的表格页面。

ASP.NET的表格控件

首先来看下ASP.NET的原生GridView控件定义:

<asp:GridView ID="Grid1" Title="表格" Width="800px" DataKeyNames="Id,Name" ShowBorder="true"runat="server" EnableCheckBoxSelect="True" AutoGenerateColumns="False"><Columns><asp:BoundField DataField="Name" DataFormatString="{0}" HeaderText="姓名" /><asp:TemplateField HeaderText="性别"><ItemTemplate><asp:Label ID="Label2" runat="server" Text='<%# GetGender(Eval("Gender")) %>'></asp:Label></ItemTemplate></asp:TemplateField><asp:BoundField DataField="EntranceYear" HeaderText="入学年份" /><asp:CheckBoxField DataField="AtSchool" HeaderText="是否在校" /><asp:HyperLinkField HeaderText="所学专业" DataTextField="Major"DataTextFormatString="{0}" DataNavigateUrlFields="Major" DataNavigateUrlFormatString="http://gsa.ustc.edu.cn/search?q={0}"Target="_blank" /><asp:ImageField DataImageUrlField="Group" DataImageUrlFormatString="~/res/images/16/{0}.png"HeaderText="分组"></asp:ImageField></Columns>
</asp:GridView>

由于GridView并不支持服务器端分页,因此我们没有设置表格的AllowPaging和PageSize属性,而是自定义了两个按钮来实现服务器端分页:

<asp:Button ID="btnPrevious" CommandName="Previous" runat="server" OnCommand="OnPageButtonClick" Text="Previous" />
<asp:Button ID="btnNext" runat="server" CommandName="Next" OnCommand="OnPageButtonClick" Text="Next" />
Page
<asp:Label runat="server" ID="lblCurrentPage"></asp:Label>
of
<asp:Label runat="server" ID="lblTotalPages"></asp:Label>  

页面第一次打开时需要加载表格数据:

protected void Page_Load(object sender, EventArgs e)
{if (!IsPostBack){BindGrid();}
}private void BindGrid()
{// 1.设置总项数int recordCount = GetTotalCount();// 2.获取当前分页数据DataTable table = GetPagedDataTable(CurrentPageIndex, PAGE_SIZE);// 3.绑定到GridGrid1.DataSource = table;Grid1.DataBind();UpdatePageControls(recordCount);
}  

绑定表格数据分为如下几个步骤:

1. 获取总记录数

2. 获取当前分页数据

3. 绑定分页数据到表格

其实,表格对象对当前分页状态一无所知(第几页,总共有几页),我们需要自己在页面上保存这些数据:

private int CurrentPageIndex
{get{var pageIndexState = ViewState["CurrentPageIndex"];if (pageIndexState == null){return 0;}else{return Convert.ToInt32(pageIndexState);}}set{ViewState["CurrentPageIndex"] = value;}
}
private const int PAGE_SIZE = 5;private int CalculatePageCount(int recordCount)
{int pageCount = recordCount / PAGE_SIZE;if (recordCount % PAGE_SIZE != 0){pageCount++;}return pageCount;
}  

将当前表格分页索引CurrentPageIndex保存到ViewState中,以便在后续的页面回发中获取分页索引。

总页数可以根据当前分页索引和每页记录数计算而来,我们将其逻辑封装到CalculatePageCount方法中。

最后,来看下UpdatePageControls方法:

private void UpdatePageControls(int recordCount)
{int pageCount = CalculatePageCount(recordCount);lblTotalPages.Text = pageCount.ToString();lblCurrentPage.Text = (CurrentPageIndex + 1).ToString();if (CurrentPageIndex == 0){btnPrevious.Enabled = false;if (pageCount > 0){btnNext.Enabled = true;}else{btnNext.Enabled = false;}}else{btnPrevious.Enabled = true;if (CurrentPageIndex == pageCount - 1){btnNext.Enabled = false;}else{btnNext.Enabled = true;}}
}  

根据当前表格分页索引和总页面设置分页按钮的状态。

此时运行页面,显示效果:

点击Next按钮时,会发起一个页面回发到后台事件:

protected void OnPageButtonClick(object sender, CommandEventArgs e)
{switch (e.CommandName){case "Previous":CurrentPageIndex--;break;case "Next":CurrentPageIndex++;break;}BindGrid();
}  

在分页按钮的点击事件中,首先根据e.CommandName来判断点击了哪个按钮,然后从ViewState中读取当前表格分页索引,最后重新绑定表格数据。

点击Next后页面截图如下:

此时页面的回发是Form表单的POST过程,因此会导致整个页面的刷新,用户体验并不好。

FineUIPro的表格控件

FineUIPro中的大部分实现代码和GridView的实现代码一样。

不过由于FineUIPro表格默认支持服务器端分页,因此无需在后台通过ViewState保存表格分页索引,也无需自己动手更新分页按钮的状态,因此代码要简单的多。

<f:PageManager ID="PageManager1" AjaxLoadingType="Mask" runat="server" />
<f:Grid ID="Grid1" Title="表格" Width="800px" DataKeyNames="Id,Name" ShowBorder="true" ShowHeader="true"AllowPaging="true" IsDatabasePaging="true" PageSize="5" runat="server" EnableCheckBoxSelect="True"OnPageIndexChange="Grid1_PageIndexChange"><Columns><f:RowNumberField /><f:BoundField DataField="Name" DataFormatString="{0}" HeaderText="姓名" /><f:TemplateField HeaderText="性别"><ItemTemplate><asp:Label ID="Label2" runat="server" Text='<%# GetGender(Eval("Gender")) %>'></asp:Label></ItemTemplate></f:TemplateField><f:BoundField DataField="EntranceYear" HeaderText="入学年份" /><f:CheckBoxField RenderAsStaticField="true" DataField="AtSchool" HeaderText="是否在校" /><f:HyperLinkField HeaderText="所学专业" DataTextField="Major"DataTextFormatString="{0}" DataNavigateUrlFields="Major" DataNavigateUrlFormatString="http://gsa.ustc.edu.cn/search?q={0}" UrlEncode="true"Target="_blank" ExpandUnusedSpace="True" /><f:ImageField DataImageUrlField="Group" DataImageUrlFormatString="~/res/images/16/{0}.png"HeaderText="分组"></f:ImageField></Columns>
</f:Grid>  

这个表格定义和之前的GridView很类似,有几点不同的地方:

1. PageManager是每一个使用FineUIPro控件的页面都需要的,其中的AjaxLoadingType用来定义AJAX回发的提示类型。

2. 表格控件的AllowPaging,IsDatabasePaging,PageSize用来指定服务器端分页和分页记录大小,这样就无需自己维护分页信息了。

3. 表格控件的PageIndexChanged用来定义服务器端分页事件。

表格列还有一些特定的属性,实现不同的显示效果:

4.1. 表格列定义了RowNumberField,用来显示行序号。

4.2 CheckBoxField的RenderAsStaticField用来指定复选框的显示样式。

4.3 HyperLinkField的ExpandUnusedSpace用来定义本列宽度占据所有未使用空间。

后台数据绑定代码很简单:

protected void Page_Load(object sender, EventArgs e)
{if (!IsPostBack){BindGrid();}
}private void BindGrid()
{// 1.设置总项数Grid1.RecordCount = GetTotalCount();// 2.获取当前分页数据DataTable table = GetPagedDataTable(Grid1.PageIndex, Grid1.PageSize);// 3.绑定到GridGrid1.DataSource = table;Grid1.DataBind();
}  

此时页面显示效果:

由于FineUIPro内置了很多主题,因此我们可以在Web.config中设置不同的主题,得到不同的显示效果:

分页事件处理函数也很简单:

protected void Grid1_PageIndexChange(object sender, GridPageEventArgs e)
{BindGrid();
}  

由于FineUIPro表格自行管理分页信息,因此我们只需要重新绑定数据即可。

此时点击下一页,页面截图:

此时的回发是AJAX POST过程,整个页面不会刷新,在回发过程中,FineUIPro会显示一个回发提示动画:

如果仅从代码和运行效果对比,我们可以看出FineUIPro的表格控件相比ASP.NET原生控件,有如下优点:

1. 代码有90%和原生控件保持一致

2. 代码更少(得益于FineUIPro表格对服务器端分页的内置支持)

3. 页面显示效果更美观大方,并且可以通过全局配置切换不同的显示样式

4. 分页过程是AJAX部分刷新,并内置了提示动画

另外,全部示例代码没有一行JavaScript和CSS代码,但是实际上FineUIPro却是严重依赖JavaScript和CSS来实现页面效果和交互。

下面我们会深入分析两个示例的异同。

页面渲染的对比

虽然两个示例的大部分ASPX和C#代码一模一样,但是从一开始两者的实现方式就完全不同。

ASP.NET的表格控件

首先来看下ASP.NET表格控件生成的页面HTML代码:

简化后看的更清楚:

<table><tr><th scope="col">姓名</th><th scope="col">性别</th><th scope="col">入学年份</th><th scope="col">是否在校</th><th scope="col">所学专业</th><th scope="col">分组</th></tr><tr><td>陈萍萍</td><td><span id="Grid1_ctl02_Label2">女</span></td><td>2000</td><td><input type="checkbox" checked="checked" disabled="disabled" /></td><td><a href="http://gsa.ustc.edu.cn/search?q=计算机应用技术" target="_blank">计算机应用技术</a></td><td><img src="../res/images/16/1.png" /></td></tr>
</table><input type="button" name="btnPrevious" value="Previous" id="btnPrevious" disabled="disabled" />
<input type="button" name="btnNext" value="Next" οnclick="javascript:__doPostBack('btnNext','')" id="btnNext" />
Page
<span id="lblCurrentPage">1</span>
of
<span id="lblTotalPages">5</span>  

可以看出:

1. ASP.NET表格渲染到页面上是<table>标签,并且包含了当前页的全部数据

2. 分页按钮最终调用的__doPostBack函数,这个函数我们并不陌生,几乎每个页面都包含这样一个默认的定义

<script type="text/javascript">
var theForm = document.forms['form1'];
if (!theForm) {theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {if (!theForm.onsubmit || (theForm.onsubmit() != false)) {theForm.__EVENTTARGET.value = eventTarget;theForm.__EVENTARGUMENT.value = eventArgument;theForm.submit();}
}
</script>  

毫无疑问,调用此回发函数,其实就是对页面上全局表单对象的提交(theForm.submit()),这将会是整个页面的刷新。

FineUIPro的表格控件

FineUIPro表格控件生成的页面HTML代码:

简化一下:

<div id="Grid1_wrapper"><div id="Grid1_tpls" class="f-grid-tpls f-hidden"><div class="f-grid-tpl" id="Grid1_ftpl_frow0_2"><span id="Grid1_ftpl_frow0_2_Label2">女</span></div>...</div>
</div><script type="text/javascript">F.load(function() {new F.Grid({renderTo: '#Grid1_wrapper',title: '表格',data: [{"f0": ["", "陈萍萍", "#@TPL@#ftpl_frow0_2", "2000", "<i class=\"f-icon f-iconfont f-grid-static-checkbox f-checked\"></i>", "<a href=\"http://gsa.ustc.edu.cn/search?q=%e8%ae%a1%e7%ae%97%e6%9c%ba%e5%ba%94%e7%94%a8%e6%8a%80%e6%9c%af\" target=\"_blank\">计算机应用技术</a>", "<img src=\"/res/images/16/1.png\" class=\"f-grid-imagefield\"></img>"],"f1": [101, "陈萍萍"],"f6": "frow0"}],paging: true,databasePaging: true,pageSize: 5,pageIndex: 0,recordCount: 22,listeners: {paging: function(event, pageIndex, oldPageIndex) {__doPostBack('Grid1', 'Page$' + pageIndex + '$' + oldPageIndex);}}});});
</script>  

可以看出:

1. 表格数据在JavaScript代码中,并渲染到页面上一个容器(Grid1_wrapper)

2. 分页事件同样触发的是__doPostBack事件

两相对比,我们可以得出如下结论:

1. ASP.NET表格控件直接渲染为table标签(包含数据)

2. FineUIPro表格控件会在页面上生成一个div占位符,然后通过JavaScript来渲染出表格控件

FineUIPro的做法更加灵活,并且可以实现更加复杂的显示效果,看下生成的DOM结构:

只所以有这么多的层次结构,是有很多原因的,简单来说:

1. FineUIPro中表格是从面板继承下来的,所以最外层的div节点是面板相关的

div.f-panel
        ->div.f-panel-header
        ->div.f-panel-bodyct
                ->div.f-panel-body

2. f-panel-body里面的层次才是表格的特定结构

div.f-panel-body

->div.f-grid-inner

->div.f-grid-headerct

->div.f-grid-bodyct

->table.f-grid-table

表格的这个特定DOM层次结构在启用列锁定时会变的更加复杂,如下所示:

启用列锁定时,f-grid-inner里面会分裂成两部分,分别对应于锁定表格和主表格,FineUIPro会负责这两部分的同步工作。

由此可知,ASP.NET表格控件直接渲染table节点和数据的方式仅适合于简单的形式,而FineUIPro为了更加好看的界面效果和更加复杂的逻辑实现,必须通过JavaScript来渲染界面和数据。而这一切对于开发人员都是透明的,FineUIPro开发人员只需要写ASPX表格和C#代码即可,剩下的交给我们。

页面回发的对比

前面分析可知,ASP.NET表格和FineUIPro的分页回发都是调用的__doPostBack函数,为什么一个是整个页面刷新,而另一个是AJAX部分刷新?

这是因为FineUIPro耍了个小把戏,重写了__doPostBack函数,翻开FineUIPro的客户端JavaScript源代码:

function _fjs_doPostBack(eventTarget, eventArgument, options) {$.ajax({type: 'POST',url: url,data: formDataBeforeAJAX,dataType: 'text',headers: {'X-FineUI-Ajax': true},success: function (data) {},error: function (xhr, textStatus) {},complete: function (xhr, textStatus) {ajaxComplete(xhr.responseText, textStatus, xhr);}});
}(function() {if (!isUND(__doPostBack)) {__originalDoPostBack = __doPostBack;__doPostBack = _fjs_doPostBack;}
})();  

这是简化后的代码,可以看到FineUIPro重新赋值:__doPostBack=_fjs_doPostBack;

而在_fjs_doPostBack中,调用了jQuery.ajax来发起AJAX请求,当然实际的实现要复杂的多,FineUIPro让这一切变得透明起来,开发人员甚至不用写一行JavaScript代码就能享受jQuery.ajax的无刷新回发。

ASP.NET表格的回发(整个页面刷新)

浏览器中F12,打开Network选项卡,观察ASP.NET表格的分页回发过程:

可以看出:

1. ASP.NET表格页面回发是整个页面刷新,返回的是完整的HTML标签(包含html,head,body....)

2. 由于是页面重新渲染,所以页面资源会重新加载,比如common.css文件

FineUIPro表格的回发(AJAX部分刷新)

浏览器中F12,打开Network选项卡,观察FineUIPro表格的分页回发过程:

可以看出,请求参数中包含X-Requested-With=XMLHttpRequest参数,说明这是一个AJAX部分刷新过程

返回的响应正文如下所示:

这是一段JavaScript代码,其中包含表格当前页的数据,并通过表格的客户端API函数来重现加载表格数据。

由于是部分刷新,页面资源无需重新加载,整个页面DOM节点也无需重建,而且响应正文的大小也要小很多。

源代码下载

下载后放到FineUIPro官网示例源代码中即可:

https://files.cnblogs.com/files/sanshi/fineuipro_database_paging.zip

小结

经过上述分析,我们可以得知,FineUIPro使用JavaScript来渲染页面,并且使用jQuery.ajax来更新页面控件。

对于开发人员来说这一切都是透明的,开发人员只需要关注ASPX和C#代码,关注自己的业务既可以了,剩下的都丢给FineUIPro来处理。

FineUIPro控件库深度解析相关推荐

  1. 第一站小红书图片裁剪控件,深度解析大厂炫酷控件

    先来看两张效果图: 哈哈,就是这样了.效果差了一些,感兴趣的小伙伴们可以运行代码感受丝滑与弹性.前段时间在竞品小红书上看到了这样的效果:图片可以跟随手指移动,双指可以(无限)放大,缩小,还可以挤压,手 ...

  2. 第一站仿小红书图片裁剪控件,深度解析大厂炫酷控件

    先来看两张效果图: 哈哈,就是这样了.效果差了一些,感兴趣的小伙伴们可以运行代码感受丝滑与弹性.前段时间在竞品小红书上看到了这样的效果:图片可以跟随手指移动,双指可以(无限)放大,缩小,还可以挤压,手 ...

  3. (四)开源C# WPF控件库《AduSkin – UI》

    微信公众号:[Dotnet9的博客],网站:[Dotnet9],问题或建议:[请网站留言], 如果对您有所帮助:[欢迎赞赏]. https://dotnet9.com 追求极致,永臻完美 A Beau ...

  4. java学习笔记(三):前端miniUI控件库入门

    java学习笔记(三):前端miniUI控件库入门 最近在一家公司实习学习,一上来就需要学习了解相关的前端内容--miniUI.而这个内容自己本身并没有了解学习过,上手也是遇到了不少的问题,于是想把自 ...

  5. UI控件库分享:DWZ(j-UI)、LigerUI、Linb

    DWZ(j-UI): 在线演示地址:http://demo.dwzjs.com 在线文档:http://demo.dwzjs.com/doc/dwz-user-guide.pdf DWZ框架Ajax开 ...

  6. [原创]基于Extjs的开源控件库 - http://extaspnet.codeplex.com/

    ExtAspNet   ExtAspNet - ExtJS based ASP.NET Controls with Full AJAX Support     ExtAspNet是一组专业的Asp.n ...

  7. Windows 公共控件库研究

    已知Windows公共控件库包含工具条控件,树视图控件,ListView控件:参见: https://blog.csdn.net/bcbobo21cn/article/details/10628767 ...

  8. Win32使用Windows公共控件库创建工具条

    Win32程序创建工具条,需要使用Windows公共控件库,是另一个DLL:本身Win32 API 是在系统自带的3个DLL: Win7,CFree 5.0:运行结果: 引入lib文件的设置如下: 如 ...

  9. asp.net控件库FineUI使用入门图解

    FineUI是一个基于 jQuery / ExtJS 的 ASP.NET 控件库,其宣传语是: 创建 No JavaScript,No CSS,No UpdatePanel,No ViewState, ...

最新文章

  1. leetcode 203 Remove Linked List Elements
  2. SUSE Linux ntp 升级报错(MAKE [1]:*** 【all】Error 2)
  3. Jmeter接口测试进阶
  4. Linux系统命令sort详解
  5. 给嵌入式工程师的一封信
  6. makefile中的函数
  7. fastapi 传输文件存文件_python3 FastAPI框架入门 基本使用, 模版渲染, 数据交互,cookie使用, 上传文件, 静态文件配置...
  8. axure html 360安装扩展,小编搞定win7系统360浏览器添加Axure扩展的设置方案
  9. appstore 客户端技术
  10. Linux网络编程复习笔记
  11. 当心路径层次太深,名字太长造成解压失败
  12. 蚂蚁课堂二期视频(每特学院二期)
  13. android.dig机器人采访,机器人学导论心得 - osc_jjc36t9p的个人空间 - OSCHINA - 中文开源技术交流社区...
  14. 安捷伦电源6319D实现GPIB通信
  15. B2C模式电商案例分享
  16. lens flare:镜头光晕
  17. Python开发【模块】:Urllib(二)
  18. 那些好看的渐变色linear-gradient(拿走不谢)
  19. Docker磁盘空间满的解决办法
  20. python查询缺失值所在位置使用scipy_在稀疏lil_matrix(Scipy / Python)中查找最大值及其索引...

热门文章

  1. IBM\浪潮\Dell\HP服务器raid(磁盘阵列)配置
  2. MySQL服务安全加固及防护
  3. Firewald 防火墙使用手册
  4. CSS webkit
  5. SpringBoot RESTful 应用中的异常处理小结
  6. 解决nginx重启“var/run/nginx/nginx.pid“ no such file or directory问题
  7. Oracle数据库中文乱码问题解决
  8. JIRA和Confluence更改JVM内存大小解决访问打开缓慢问题
  9. 如何解决“本地编辑,更新时传入删除”消息
  10. 如何在Android按钮上以编程方式设置drawableLeft?