2023年2月

在Web开发的时候,我们很多时候,需要引用很多CSS文件、JS文件,随着使用更多的插件或者独立样式文件,可能我们的Web界面代码会越来越臃肿,看起来也很累赘,在MVC里面提供了一个Bundle的对象,用来简化页面代码非常方便,本文主要介绍在我的MVC框架里面,如何使用bundles来简化页面的代码的。

1、常规的页面代码

我们知道,随着使用更多的一些效果,我们可能不断引入一些新的JS和CSS文件,已达到Web界面更好的表现效果。这样也就逐步增加了文件代码的行数,造成相对比较臃肿的场景,如下面的我正常使用的Web界面,头部需要引入很多JS和CSS文件。

@*添加Jquery EasyUI的样式*@<linkhref="~/Content/JqueryEasyUI/themes/default/easyui.css"rel="stylesheet"type="text/css" />
    <linkhref="~/Content/JqueryEasyUI/themes/icon.css"rel="stylesheet"type="text/css" />

    <linkhref="~/Content/themes/Default/style.css"rel="stylesheet"type="text/css" />
    <linkhref="~/Content/themes/Default/default.css"rel="stylesheet"type="text/css" />@*添加Jquery,EasyUI和easyUI的语言包的JS文件*@<scripttype="text/javascript"src="~/Content/JqueryEasyUI/jquery.min.js"></script>
    <scripttype="text/javascript"src="~/Content/JqueryEasyUI/jquery.easyui.min.js"></script>
    <scripttype="text/javascript"src="~/Content/JqueryEasyUI/locale/easyui-lang-zh_CN.js"></script>@*日期格式的引用*@<scriptsrc="~/Content/datapattern.js"></script>
    
    <!--引用EasyUI扩展-->
    <linkhref="~/Content/JQueryTools/jQuery.easyui-extend/extend/themes/easyui.extend.css"rel="stylesheet" />
    <linkhref="~/Content/JQueryTools/jQuery.easyui-extend/extend/themes/icon.css"rel="stylesheet" />
    <scriptsrc="~/Content/JQueryTools/jQuery.easyui-extend/jquery.easyui.extend.min.js"></script>@*引用提示控件*@<linkrel="stylesheet"type="text/css"href="~/Content/JQueryTools/jNotify/jquery/jNotify.jquery.css"media="screen" />
    <scripttype="text/javascript"src="~/Content/JQueryTools/jNotify/jquery/jNotify.jquery.js"></script>@*常用的一些组件业务脚本函数*@<scripttype="text/javascript"src="~/Scripts/ComponentUtil.js"></script>

然后这样的文件总是在不断的复制做,非常不雅观,维护也不方便。

在ASP.NET MVC出来之后,引入了一个叫做Bundle的东西,它用来将js和css文件捆绑为一个块进行输出,能够极大简化界面代码,并默认对这些内容进行压缩处理,提高效率。

最终简化的界面代码如下所示。

@using System.Web.Optimization;
@Scripts.Render("~/bundles/jquery")
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/jquerytools")
@Styles.Render("~/Content/jquerytools")

2、使用bundles优化的界面操作

为了实现上面的效果,我们需要进行几步的操作处理。

在App_Start里面的BundleConfig里面增加几行处理代码,如下所示。

    public classBundleConfig
{
//有关 Bundling 的详细信息,请访问http://go.microsoft.com/fwlink/?LinkId=254725 public static voidRegisterBundles(BundleCollection bundles)
{
//为了减少太多的Bundles命名,定义的CSS的Bundle为:"~/Content/css"、"~/Content/jquerytools"//定义的Script的Bundles为:"~/bundles/jquery"、"~/bundles/jquerytools"//Jquery必备的StyleBundle和ScriptBundle StyleBundle css = new StyleBundle("~/Content/css");
ScriptBundle jquery
= new ScriptBundle("~/bundles/jquery");//添加Jquery EasyUI的样式 css.Include("~/Content/JqueryEasyUI/themes/default/easyui.css","~/Content/JqueryEasyUI/themes/icon.css","~/Content/themes/Default/style.css","~/Content/themes/Default/default.css");//添加Jquery,EasyUI和easyUI的语言包的JS文件,日期格式的引用 jquery.Include("~/Content/JqueryEasyUI/jquery.min.js","~/Content/JqueryEasyUI/jquery.easyui.min.js","~/Content/JqueryEasyUI/locale/easyui-lang-zh_CN.js","~/Content/datapattern.js");//常用的一些组件业务脚本函数(建议放到最后) jquery.Include("~/Scripts/ComponentUtil.js");//扩展的StyleBundle和ScriptBundle StyleBundle cssExtend = new StyleBundle("~/Content/jquerytools");
ScriptBundle jqueryExtend
= new ScriptBundle("~/bundles/jquerytools");//引用EasyUI扩展 cssExtend.Include("~/Content/JQueryTools/jQuery.easyui-extend/extend/themes/easyui.extend.css","~/Content/JQueryTools/jQuery.easyui-extend/extend/themes/icon.css");
jqueryExtend.Include(
"~/Content/JQueryTools/jQuery.easyui-extend/jquery.easyui.extend.min.js");//引用消息提示控件 cssExtend.Include("~/Content/JQueryTools/jNotify/jquery/jNotify.jquery.css");
jqueryExtend.Include(
"~/Content/JQueryTools/jNotify/jquery/jNotify.jquery.js");//其他一些辅助脚本和样式//全部增加到集合里面去 bundles.Add(css);
bundles.Add(jquery);
bundles.Add(cssExtend);
bundles.Add(jqueryExtend);
}
}

上面代码,我们增加一些必要的Jquery和一些扩展给的JqueryTool的脚本和样式,方便统一化管理。

默认的情况下,Bundle是按照字母顺序进行排序的,如果需要按照增加的次序进行排序,这需要写一个自定义的排序规则进行处理,如下所示

    /// <summary>
    ///自定义Bundles排序/// </summary>
    internal classAsIsBundleOrderer : IBundleOrderer
{
public virtual IEnumerable<BundleFile> OrderFiles(BundleContext context, IEnumerable<BundleFile>files)
{
returnfiles;
}
}

然后在调用的时候,修改对象的排序规则即可。

            ScriptBundle jqueryExtend = new ScriptBundle("~/bundles/jquerytools");
jqueryExtend.Orderer
= new AsIsBundleOrderer();

接着在Global.asa.cs里面,增加对Bundle的注册,如下所示。

        protected voidApplication_Start()
{
AreaRegistration.RegisterAllAreas();
BundleConfig.RegisterBundles(BundleTable.Bundles);

WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}

最后在MVC的视图里面,就可以使用Bundle来简化界面代码了。简化后的界面代码如下所示。

<!DOCTYPE html>
<html>
    <head>
    <title>用户管理</title>
    <metaname="viewport"content="width=device-width" />@using System.Web.Optimization;
@Scripts.Render("~/bundles/jquery")
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/jquerytools")
@Styles.Render("~/Content/jquerytools")

...............

运行界面,虽然使用了简化版本的代码,依旧正常运行

页面代码输出则还是和原先未优化的一致。

<!DOCTYPE html>
<html>
    <head>
    <title>用户管理</title>
    <metaname="viewport"content="width=device-width" />
    <scriptsrc="/Content/JqueryEasyUI/jquery.min.js"></script>
    <scriptsrc="/Content/JqueryEasyUI/jquery.easyui.min.js"></script>
    <scriptsrc="/Content/JqueryEasyUI/locale/easyui-lang-zh_CN.js"></script>
    <scriptsrc="/Content/datapattern.js"></script>
    <scriptsrc="/Scripts/ComponentUtil.js"></script>

    <linkhref="/Content/JqueryEasyUI/themes/default/easyui.css"rel="stylesheet"/>
    <linkhref="/Content/JqueryEasyUI/themes/icon.css"rel="stylesheet"/>
    <linkhref="/Content/themes/Default/style.css"rel="stylesheet"/>
<linkhref="/Content/themes/Default/default.css"rel="stylesheet"/>

<scriptsrc="/Content/JQueryTools/jQuery.easyui-extend/jquery.easyui.extend.min.js"></script>
    <scriptsrc="/Content/JQueryTools/jNotify/jquery/jNotify.jquery.js"></script>

    <linkhref="/Content/JQueryTools/jQuery.easyui-extend/extend/themes/easyui.extend.css"rel="stylesheet"/>
    <linkhref="/Content/JQueryTools/jQuery.easyui-extend/extend/themes/icon.css"rel="stylesheet"/>
    <linkhref="/Content/JQueryTools/jNotify/jquery/jNotify.jquery.css"rel="stylesheet"/>

基于MVC4+EasyUI的Web开发框架的系列文章:

基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍


基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计

基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用

基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用

基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍

基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作

基于MVC4+EasyUI的Web开发框架形成之旅--权限控制

基于MVC4+EasyUI的Web开发框架经验总结(1)-利用jQuery Tags Input 插件显示选择记录

基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面

基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据

基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts

基于MVC4+EasyUI的Web开发框架经验总结(5)--使用HTML编辑控件CKEditor和CKFinder

基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理

基于MVC4+EasyUI的Web开发框架经验总结(7)--实现省份、城市、行政区三者联动

基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览

基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作

基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出

基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码

基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式

基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度

基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作

在基于MVC4+EasyUI的Web开发框架里面,大量采用了Jquery的方法,对数据进行请求或者提交,方便页面和服务器后端进行数据的交互处理。本文主要介绍利用Jquery处理数据交互的几种方式,包括获取数据并显示,插入新数据到服务器,更新数据,删除数据等操作。

1、利用Jquery获取数据并显示

为了顺利获取数据,我们需要保持页面端调用和服务器端保持一致,并相应的把数据转换或者封装为对象实体进行处理。

下面我们以一个简单的全国省份、全国城市、全国城市行政区的案例进行Demo代码的介绍。


总体的操作包括了,分页查询,添加数据的保存,编辑显示和保存,查看信息的数据显示等等,而利用Jquery获取数据并绑定到界面控件上的代码操作如下所示,主要就是利用getJson方法进行处理。

        //绑定编辑详细信息的方法
function BindEditInfo(ID) {//使用同步方式,使得联动的控件正常显示
            $.ajaxSettings.async = false;//首先用户发送一个异步请求去后台实现方法
            $.getJSON("/Province/FindByID?id=" +ID, function (info) {//赋值有几种方式:.datebox('setValue', info.Birthday);.combobox('setValue', info.Status);.val(info.Name);.combotree('setValue', info.PID);.numberbox('setValue', info.Number);
                $("#ID").val(info.ID);
$(
"#ProvinceName").val(info.ProvinceName);

isAddOrEdit
= 'edit';//新增对话框标识 });
}
//绑定查看详细信息的方法 function BindViewInfo(ID) {//发送请求 $.getJSON("/Province/FindByID?id=" +ID, function (info) {
$(
"#ID2").text(info.ID);
$(
"#ProvinceName2").text(info.ProvinceName);
});
}

getJson方法主要就是调用MVC里面控制器的方法,获取数据,并把它转换为Json的对象实体,这样我们就能方便获取到对应的属性,从而绑定到界面控件。而FindByID的接口是控制器里面的方法定义,我们可以通过下面的控制器基类代码了解具体的逻辑。

        /// <summary>
        ///查询数据库,检查是否存在指定ID的对象/// </summary>
        /// <param name="id">对象的ID值</param>
        /// <returns>存在则返回指定的对象,否则返回Null</returns>
        public virtual ActionResult FindByID(stringid)
{
//检查用户是否有权限,否则抛出MyDenyAccessException异常 base.CheckAuthorized(AuthorizeKey.ViewKey);

ActionResult result
= Content("");
T info
=baseBLL.FindByID(id);if (info != null)
{
result
=ToJsonContentDate(info);
}
returnresult;
}
        /// <summary>
        ///返回处理过的时间的Json字符串/// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public ContentResult ToJsonContentDate(objectdate)
{
var timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss"};returnContent(JsonConvert.SerializeObject(date, Formatting.Indented, timeConverter));
}

2、利用Jquery保存数据到服务器

上面的操作是从服务端获取数据并显示在页面上,下面我们来介绍如何把数据通过通过Jquery调用,保存到服务器上。

在Web框架里面,我们把添加数据和编辑数据的界面,共享了一个层的界面代码,这样可以减少主界面视图Index.cshtml的代码数量(因为我们把各种界面的代码放在一个文件里面,方便操作管理)。

    <!--------------------------添加/修改信息的弹出层---------------------------->
    <divid="DivAdd"class="easyui-dialog"style="width:680px;height:200px;padding:10px 20px"closed="true"resizable="true"modal="true"data-options="iconCls: 'icon-add',buttons: '#dlg-buttons'">
        <formid="ffAdd"method="post"novalidate="novalidate">
            <divid="tabAdd"class="easyui-tabs" >
                <divtitle="基本信息"data-options="iconCls:'icon-view'"style="padding:5px 5px">
                    <table>
                        <tr>
                            <td>                    
                                <tableid="tblAdd1"class="view">
                                    <tr> 
                                        <th>
                                            <labelfor="ProvinceName">省份名称:</label>
                                        </th>
                                        <tdcolspan="3">
                                            <inputclass="easyui-validatebox"type="text"id="ProvinceName"name="ProvinceName"style="width:280px;"  />
                                        </td>
 
                                    </tr>
                                 </table>
                            </td>
                        </tr>
                    </table>
                </div>
            </div>
            <divstyle="text-align:right; padding-top:10px">
                <inputtype="hidden"id="ID"name="ID" />
                <ahref="javascript:void(0)"class="easyui-linkbutton"id="btnAddOK"iconcls="icon-ok"onclick="SaveEntity()">确定</a>
                <ahref="javascript:void(0)"class="easyui-linkbutton"iconcls="icon-cancel"onclick="javascript:$('#DivAdd').dialog('close')">关闭</a>
            </div>
         </form>
    </div>

而数据的保存,我们也用同一个函数,这样也很方便,同时减少代码数量,保存操作的javascript脚本函数如下所示。

        //绑定添加按钮的事件
        functionSaveEntity() {//判断表单的信息是否通过验证
            var validate = $("#ffAdd").form('validate');if (validate == false) {return false;
}
var postData = $("#ffAdd").serializeArray();
$.post(url, postData,
function(json) {var data =$.parseJSON(json);if(data.Success) {//添加成功 1.关闭弹出层,2.刷新DataGird showTips("保存成功");
$(
"#DivAdd").dialog("close");
$(
"#grid").datagrid("reload");
$(
"#ffAdd").form("clear");
}
else{
showError(
"保存失败:" + data.ErrorMessage, 3000);
}
}).error(
function() {
$.messager.alert(
"提示", "您未被授权使用该功能,请联系管理员进行处理。", 'warning');
});
}

由于每个层都定义了Name和ID,因此我们可以很容易通过下面方式获取到对应的对象数据,方便提交。

var postData = $("#ffAdd").serializeArray();

插入数据的时候,调用的路径如下所示:

url = '/Province/Insert';

更新数据的时候,调用的路径如下数艘:

url = '/Province/Update?ID=' + ID;

插入对象到数据库里面的控制器方法,主要还是调用BLL层的对象方法进行处理,不过事先会进行一定的权限控制和信息补充,如下代码所示。

        /// <summary>
        ///插入指定对象到数据库中/// </summary>
        /// <param name="info">指定的对象</param>
        /// <returns>执行操作是否成功。</returns>
        public virtualActionResult Insert(T info)
{
//检查用户是否有权限,否则抛出MyDenyAccessException异常 base.CheckAuthorized(AuthorizeKey.InsertKey);

CommonResult result
= newCommonResult();if (info != null)
{
try{
OnBeforeInsert(info);
result.Success
=baseBLL.Insert(info);
}
catch(Exception ex)
{
LogTextHelper.Error(ex);
//错误记录 result.ErrorMessage =ex.Message;
}
}
returnToJsonContent(result);
}

我们注意到,插入和更新操作,返回的对象都是
CommonResult
对象,这个对象,包含了一个Success的布尔属性,用来表示是否成功,还有一个ErrorMessage属性,用来标识错误信息的,所以我们利用Javascript脚本处理保存操作的时候,也需要使用这两个属性,用来区分和提示信息的显示。

                var data =$.parseJSON(json);if(data.Success) {//添加成功  1.关闭弹出层,2.刷新DataGird
                    showTips("保存成功");
$(
"#DivAdd").dialog("close");
$(
"#grid").datagrid("reload");
$(
"#ffAdd").form("clear");
}
else{
showError(
"保存失败:" + data.ErrorMessage, 3000);
}

操作完成后,提示成功的信息如下所示。

3、利用Jquery删除列表数据操作

利用Jquery函数,可以POST删除的请求到服务器上,在此之前我们需要了解我们需要删除那些记录,并确认提示是否删除,删除成功后,更新列表,并提示用户,大致的页面代码函数如下所示。

        //实现删除数据的方法
        functionDelete() {//得到用户选择的数据的ID
            var rows = $("#grid").datagrid("getSelections");if (rows.length >= 1) {//遍历出用户选择的数据的信息,这就是用户用户选择删除的用户ID的信息
                var ids = "";   //1,2,3,4,5
                for (var i = 0; i < rows.length; i++) {
ids
+= rows[i].ID + ",";
}
//最后去掉最后的那一个, ids = ids.substring(0, ids.length - 1);var postData = { Ids: ids };//然后确认发送异步请求的信息到后台删除数据 $.messager.confirm("删除确认", "您确认删除选定的记录吗?", function(action) {if(action) {
$.ajax({
type:
'POST',
url:
'/District/DeletebyIds',
dataType:
'json',
data: postData,
success:
function(data) {if(data.Success) {
showTips(
"删除选定的记录成功");

$(
"#grid").datagrid("reload");//当删除完成之后,第二次删除的时候还记得上次的信息,这样是不可以的,所以我们需要清除第一次的信息 rows.length = "";//第一种方法 $("#grid").datagrid("clearSelections");//第二种方法 }else{
showError(
"操作失败:" + data.ErrorMessage, 3000);
}
}
});
}
});
}
else{
$.messager.alert(
"提示", "请选择你要删除的数据");
}
}

而服务器的MVC控制器类,我们也只需要调用基类控制器方法就可以了,基本上不需要额外的处理代码。

MVC控制器基类的方法定义如下所示,注意最后返回的是一个常见类CommonResult ,承载这个是否操作成功和错误信息(如果存在的话)。

        /// <summary>
        ///删除多个ID的记录/// </summary>
        /// <param name="ids">多个id组合,逗号分开(1,2,3,4,5)</param>
        /// <returns></returns>
        public virtual ActionResult DeleteByIds(stringids)
{
//检查用户是否有权限,否则抛出MyDenyAccessException异常 base.CheckAuthorized(AuthorizeKey.DeleteKey);

CommonResult result
= newCommonResult();try{if (!string.IsNullOrEmpty(ids))
{
List
<string> idArray = ids.ToDelimitedList<string>(",");foreach (string strId inidArray)
{
if (!string.IsNullOrEmpty(strId))
{
baseBLL.Delete(strId);
}
}
result.Success
= true;
}
}
catch(Exception ex)
{
LogTextHelper.Error(ex);
//错误记录 result.ErrorMessage =ex.Message;
}
returnToJsonContent(result);
}

城市信息界面如下所示。

行政区管理界面如下所示。

基于MVC4+EasyUI的Web开发框架的系列文章:

基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍


基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计

基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用

基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用

基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍

基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作

基于MVC4+EasyUI的Web开发框架形成之旅--权限控制

基于MVC4+EasyUI的Web开发框架经验总结(1)-利用jQuery Tags Input 插件显示选择记录

基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面

基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据

基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts

基于MVC4+EasyUI的Web开发框架经验总结(5)--使用HTML编辑控件CKEditor和CKFinder

基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理

基于MVC4+EasyUI的Web开发框架经验总结(7)--实现省份、城市、行政区三者联动

基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览

基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作

基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出

基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码

基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式

基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度

基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作

在默认情况下,EasyUI的DataGrid好像都没有具备自动宽度的适应功能,一般是指定像素宽度的,但是使用的人员计算机的屏幕分辨率可能不一样,因此导致有些地方显示太大或者太小,总是不能达到好的预期效果,如果DataGrid能够根据窗口尺寸进行伸缩,效果应该好很多。本文主要介绍DataGrid控件实现自动适应宽带高度的操作。

首先我们需要定义一个resizeDataGrid的扩展函数,方便在页面里面进行调用,扩展函数定义如下所示。

//datagrid宽度高度自动调整的函数
$.fn.extend({
resizeDataGrid:
function(heightMargin, widthMargin, minHeight, minWidth) {var height = $(document.body).height() -heightMargin;var width = $(document.body).width() -widthMargin;
height
= height < minHeight ?minHeight : height;
width
= width < minWidth ?minWidth : width;
$(
this).datagrid('resize', {
height: height,
width: width
});
}
});

定义好上面的函数后,我们就可以在页面里面使用Javascript进行调用,调用方法如下所示:$('#grid').resizeDataGrid。

        var heightMargin = $("#toolbar").height() + 60;var widthMargin = $(document.body).width() - $("#tb").width();//第一次加载时和当窗口大小发生变化时,自动变化大小
        $('#grid').resizeDataGrid(heightMargin, widthMargin, 0, 0);
$(window).resize(
function() {
$(
'#grid').resizeDataGrid(heightMargin, widthMargin, 0, 0);
});

通过上面的代码,我们就可以定义两个高度、宽度的边界,但是这些我们不应该固定化,应该通过一些界面代码的对象动态获取边框大小。

HTML代码如下所示。

    <divid="tb"style="padding:5px;height:auto">
        <!-------------------------------搜索框----------------------------------->
        <fieldset>
            <legend>信息查询</legend>
            <formid="ffSearch"method="post">
                <divid="toolbar">
                    <tablecellspacing="0"cellpadding="0">
                        <tr>
                             <th>
                                <labelfor="txtProvinceName">省份名称:</label>
                            </th>
                            <td>
                                <inputtype="text"ID="txtProvinceName"name="txtProvinceName"style="width:100px"  />
                            </td>
                            <tdcolspan="2">
                                <ahref="#"class="easyui-linkbutton"data-options="iconCls:'icon-search'"id="btnSearch">查询</a>
                                <ahref="javascript:void(0)"class="easyui-linkbutton"id="btnImport"iconcls="icon-excel"onclick="ShowImport()">导入</a>
                                <ahref="javascript:void(0)"class="easyui-linkbutton"id="btnExport"iconcls="icon-excel"onclick="ShowExport()">导出</a>
                            </td>
                          </tr>
                    </table>
                </div>
            </form>
        </fieldset>
                
        <!-------------------------------详细信息展示表格----------------------------------->
        <tableid="grid"style="width: 940px"title="用户操作"data-options="iconCls:'icon-view'">            
        </table>
    </div>

这个界面效果如下所示。

其他类似的界面类似效果如下所示。

对比上面的界面,下面的界面增加了左边一个面板,这里的代码也不需要特殊的设置。

            var heightMargin = $("#toolbar").height() + 40;var widthMargin = $(document.body).width() - $("#tb").width() + 20;//第一次加载时和当窗口大小发生变化时,自动变化大小
            $('#grid').resizeDataGrid(heightMargin, widthMargin, 0, 0);
$(window).resize(
function() {
$(
'#grid').resizeDataGrid(heightMargin, widthMargin, 0, 0);
});

上面的代码也只是根据效果进行了一些微调,基本和第一部分的设置宽度代码差不多。

也可以使用布局 class="easyui-layout" 进行调整,使DataGrid表格能够进行自动调整。

    <divclass="easyui-layout"data-options="fit:true"id="tb">
        <div data-options="region:'north'"style="padding:5px;height:70px">
            <!-------------------------------搜索框----------------------------------->
            <fieldset>
                <legend>信息查询</legend>
                <formid="ffSearch"method="post">
                    <divid="toolbar">
                        <tablecellspacing="0"cellpadding="0">
                            <tr>
                                <th>
                                    <labelfor="txtProvinceName">省份名称:</label>
                                </th>
                                <td>
                                    <inputtype="text"id="txtProvinceName"name="txtProvinceName"style="width:100px" />
                                </td>
                                <tdcolspan="2">
                                    <ahref="#"class="easyui-linkbutton"data-options="iconCls:'icon-search'"id="btnSearch">查询</a>
                                    <ahref="javascript:void(0)"class="easyui-linkbutton"id="btnImport"iconcls="icon-excel"onclick="ShowImport()">导入</a>
                                    <ahref="javascript:void(0)"class="easyui-linkbutton"id="btnExport"iconcls="icon-excel"onclick="ShowExport()">导出</a>
                                </td>
                            </tr>
                        </table>
                    </div>
                </form>
            </fieldset>
        </div>
       <div data-options="region:'center'">
            <!-------------------------------详细信息展示表格----------------------------------->
            <tableid="grid"title="用户操作"data-options="iconCls:'icon-view'"fit="true"></table>
        </div>
    </div>

基于MVC4+EasyUI的Web开发框架的系列文章:

基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍


基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计

基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用

基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用

基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍

基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作

基于MVC4+EasyUI的Web开发框架形成之旅--权限控制

基于MVC4+EasyUI的Web开发框架经验总结(1)-利用jQuery Tags Input 插件显示选择记录

基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面

基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据

基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts

基于MVC4+EasyUI的Web开发框架经验总结(5)--使用HTML编辑控件CKEditor和CKFinder

基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理

基于MVC4+EasyUI的Web开发框架经验总结(7)--实现省份、城市、行政区三者联动

基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览

基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作

基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出

基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码

基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式

基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度

基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作

在很多Web系统中,一般都可能提供一些图标的选择,方便配置按钮,菜单等界面元素的图标,从而是Web系统界面看起来更加美观和协调。但是在系统中一般内置的图标样式相对比较有限,而且硬编码写到样式表里面,这样给我们扩展使用有很多的不方便。基于这个原因,我想如果能够独立一个模块,自动根据图标生成图标CSS样式文件,并存储相应的记录到数据库里面,方便我们查询显示,那样我们使用起来就很方便了,最后有了这些数据,只需要做一个通用的图标选择界面,并可以在很多地方重用了。本文正是基于这个思路,开发了一个图标管理模块和图标选择界面,本文主要阐述这个开发过程和最终的效果展示。

1、图标样式生成管理

为了方便根据读取的图标文件列表,生成对应的图标样式文件,我们可以利用NVelocity组件,基于模板进行CSS样式文件的生成。关于NVelocity的使用,可以参考我多篇关于它的介绍,这个组件非常强大,我自己的代码生成工具也是基于它编写了很多模板进行代码生成,具体可以参考一下《
使用NVelocity生成内容的几种方式
》这篇文章。

1.1 图标样式文件准备

有了这些准备,我们可以定义一个模板的文件用来生成样式文件了,我们先看最终的样式文件效果。

.icon-table{background:url('table.png') no-repeat center center;
}.icon-telephone{background:url('telephone.png') no-repeat center center;
}.icon-user{background:url('user.png') no-repeat center center;
}.icon-view{background:url('view.png') no-repeat center center;
}.icon-word{background:url('word.png') no-repeat center center;
}
 

根据以上组织效果,我们可以定义一个模板内容如下所示。

#foreach($item in ${FileNameList})
.$
{item.Text}{background:url('${item.Value}') no-repeat center center;
}
#end ##endforeach

其中FileNameList变量是一个基于名称和值的集合对象,我们遍历它进行生成就可以了。

1.2 图标样式的生成操作

有了模板,我们还需要组织好对应的文件目录,一般来说,Web的图标可以使用16,24,32这些标准大小的图表,适应不同场合的需要。

因此我们创建几个不同的目录,并放入对应的模板文件和图标文件。

生成图标样式文件的操作分为下面几个步骤:

获取对应目录的图标文件,转换为实际的对象格式集合,生成图标样式文件,存储图表样式到数据库方便查询。

这些操作我们在图标管理的控制器
IconController
里面增加方法完成,部分代码如下所示。

        /// <summary>
        ///生成图标文件/// </summary>
        /// <param name="iconSize">图表尺寸,可选16,32等</param>
        /// <returns></returns>
        public ActionResult GenerateIconCSS(int iconSize = 16)
{
CommonResult result
= newCommonResult();string realPath = Server.MapPath("~/Content/icons-customed/" +iconSize);if(Directory.Exists(realPath))
{
List
<CListItem> list =GetImageToList(realPath, iconSize);try{//使用相对路径进行构造处理 string template = string.Format("Content/icons-customed/{0}/icon.css.vm", iconSize);
NVelocityHelper helper
= newNVelocityHelper(template);
helper.AddKeyValue(
"FileNameList", list);

helper.FileNameOfOutput
= "icon";
helper.FileExtension
= ".css";
helper.DirectoryOfOutput
= realPath;//指定实际路径 string outputFilePath = helper.ExecuteFile();if (!string.IsNullOrEmpty(outputFilePath))
{
result.Success
= true;//写入数据库 bool write = BLLFactory<Icon>.Instance.BatchAddIcon(list, iconSize);
}
}
catch(Exception ex)
{
LogTextHelper.Error(ex);
result.ErrorMessage
=ex.Message;
}
}
else{
result.ErrorMessage
= "没有找到图片文件";
}
returnToJsonContent(result);
}

上面的方法很好的完成了对图标样式的生成和保存数据库的操作,这个生成操作主要就是基于模板化的生成,非常方便。

在构建名称值的集合的时候,注意图标样式名称,不能包含有 一些特殊的字符,如[]()这些符号需要去掉,因此可以通过下面的正则表达式替换方法进行去除。

                    string displayText =Path.GetFileNameWithoutExtension(file);//文件名需要去除()和[]等符号
                    displayText = CRegex.Replace(displayText, @"[)\];,\t\r ]|[\n]", "", 0);
displayText
= CRegex.Replace(displayText, @"[(\[]", "-", 0);

最终,我们可以构建一个独立的页面,用来实现生成图标样式并保存的操作,界面如下所示。

界面操作代码如下所示。

            //绑定按钮的的点击事件
            functionBindEvent() {                
$(
"#btnGenerateCSS").click(function() {
$.messager.confirm(
"操作确认", "您确认重新生成图标记录吗?", function(action) {if(action) {//图表尺寸 var iconSize = $("#IconSize").combobox('getValue');//alert(iconSize); var postData = "";

$.ajax({
type:
'POST',
url:
'/Icon/GenerateIconCSS?iconSize=' +iconSize,
dataType:
'json',
data: postData,
success:
function(data) {if(data.Success) {
showTips(
"操作成功");
location.reload();
}
else{
showError(
"操作失败:" + data.ErrorMessage, 3000);
}
}
});
}
});
});
}

2、图标的分页展示

为了有效查看我们生成在数据库的图标列表,我们需要一个合理的界面表现方式,用来显示图标信息。传统的使用datagrid的方式比较呆板,也不是很方便,所以我们需要自定义分页处理进行展现,基于重用一些优秀组件的原则,我侧重于使用一些现成的组件模块,MVC分页方面,考虑使用杨涛的MVC分页控件(http://www.webdiyer.com/mvcpager/),这个功能看起来很不错。

图表的展现方式,我希望通过easyui的这个例子进行展现一组图表的效果。

2.1 图表展现的界面效果

然后系统通过把它们进行分页处理,选择一些好的分页样式表现方式

最终实现的图表样式显示效果如下所示。

小图标效果如下所示。

大图标效果如下所示。

2.2 图标的分页处理操作

杨涛的分页控件,提供了很多绑定分页的方式,不过都主要是基于MVC的模型数据处理,在我的Web框架里面主要利用JS绑定数据,有 一定的差异,但是既然大家都是MVC应用,整合还是没问题的。

为了展现上面的效果,我们需要建立一个表单查询的内容,代码如下所示。

            <fieldset>
                <legend>功能操作</legend>@using (Html.BeginForm("select", "Icon", new RouteValueDictionary { { "id", "" } }, FormMethod.Get))
{
<span>尺寸:</span> <selectclass="easyui-combobox"id="IconSize"name="IconSize"style="width:100px"> <optionvalue="16">16×16</option> <optionvalue="24">24×24</option> <optionvalue="32">32×32</option> </select> <inputtype="submit"value="搜索(S)"accesskey="S" />}</fieldset>

数据内容的展现,主要就是利用了easyUI的样式,创建一些linkbutton的代码,代码如下所示。这里注意的是,我也是用了model,它是PagedList<WHC.MVCWebMis.Entity.IconInfo>类型的。

也就是说,最终这个视图界面后台,是有一个模型的绑定的。

        <divid="contents">@using Webdiyer.WebControls.Mvc;
@model PagedList
<WHC.MVCWebMis.Entity.IconInfo>@foreach (var item in Model)
{
<ahref="javascript:void(0)"class="easyui-linkbutton"onclick="SelectItem(this, '@item.IconCls')"id="@item.ID"data-options="plain:true,iconCls:'@item.IconCls',size:'large',toggle:true"> </a>}</div>

图标后台处理的控制器方法如下所示。

        /// <summary>
        ///根据条件获取基于PagedList的对象集合,并返回给分页视图使用/// </summary>
        /// <param name="id">分页页码</param>
        /// <param name="iconsize">图标尺寸</param>
        /// <returns></returns>
        private PagedList<IconInfo> GetPageList(int? id, int? iconsize = 16)
{
int size = iconsize ?? 16;int pageIndex = id ?? 1;int pageSize = 200;

PagerInfo pagerInfo
= newPagerInfo();
pagerInfo.CurrenetPageIndex
=pageIndex;
pagerInfo.PageSize
=pageSize;string where = string.Format("iconsize = {0}", size);
List
<IconInfo> list = BLLFactory<Icon>.Instance.FindWithPager(where, pagerInfo);
PagedList
<IconInfo> pageList = pageList = new PagedList<IconInfo>(list, pageIndex, pageSize, pagerInfo.RecordCount);returnpageList;
}
/// <summary> ///根据条件获取分页数据集合,并绑定到视图里面/// </summary> /// <param name="id">分页页码</param> /// <param name="iconsize">图标尺寸</param> /// <returns></returns> public ActionResult Select(int? id = 1, int? iconsize = 16)
{
PagedList
<IconInfo> pageList =GetPageList(id, iconsize);return View("select", pageList);
}

最后部分是分页部分的展现了,就是在底部展现各页的页码等信息了。

这个部分很简单,代码如下所示。

        <div>
            <divstyle="float:left;width:50%">共 @Model.TotalPageCount 页 @Model.TotalItemCount 条记录,当前为第 @Model.CurrentPageIndex 页</div>@Html.Pager(Model, new PagerOptions { PageIndexParameterName = "id" }, new { style = "float:right", id = "badoopager" })</div>

在分页的时候,可能很多时候,发现更新页面后,条件就消失了,这种情况是因为没有很好绑定条件的值到界面上,我们可以通过页面加载完成后,把URL里面的参数值赋值给控件就可以了。

        $(function() {var iconSize = '@Request.QueryString["iconSize"]';if(iconSize != undefined && iconSize != "")
{
$(
"#IconSize").combobox('setValue', iconSize);
}
});

这样图表大小的条件就一直可以保持正确的内容,提交表单后依旧可以正常保持了。

3、图标的选择

既然生成了图标文件,并且构建了图标的展示界面,那么我们就需要在一些需要配置图标的地方,能够提供一个界面选择图标了。

绑定弹出选择图标界面操作,在EasyUI的基础上,使用了扩展对话框的操作,可以弹出一个外部页面的选择图标菜单。

        functionSelectIcon(id, value) {
$.showWindow({
title:
'选择图标',
useiframe:
true,
width:
960,
height:
640,
content:
'url:/Icon/Select',
data: { id: $(id), value: $(value) },
buttons: [{
text:
'OK',
iconCls:
'icon-ok',
handler:
'doOK' //此方法在_content3.html中 }, {
text:
'取消',
iconCls:
'icon-cancel',
handler:
function(win) {
win.close();
}
}],
onLoad:
function(win, content) {//window打开时调用,初始化form内容 if(content) {
content.doInit(win);
}
}
});
}
//绑定选择按钮的事件 functionBindSelectIconEvent() {
$(
"#tdIcon").click(function () { SelectIcon("#imgIcon", "#WebIcon") });
$(
"#tdIcon1").click(function () { SelectIcon("#imgIcon1", "#WebIcon1") });
}

选择好每个图标后,我们就会返回到主界面上,并设置好主界面上的图表样式,让它显示出我们选择的图标效果。

基于MVC4+EasyUI的Web开发框架的系列文章:

基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍


基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计

基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用

基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用

基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍

基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作

基于MVC4+EasyUI的Web开发框架形成之旅--权限控制

基于MVC4+EasyUI的Web开发框架经验总结(1)-利用jQuery Tags Input 插件显示选择记录

基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面

基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据

基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts

基于MVC4+EasyUI的Web开发框架经验总结(5)--使用HTML编辑控件CKEditor和CKFinder

基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理

基于MVC4+EasyUI的Web开发框架经验总结(7)--实现省份、城市、行政区三者联动

基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览

基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作

基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出

基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码

基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式

基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度

基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作

RDLC是一个不错的报表,有着比较不错的设计模式和展现效果,在我的Winform开发里面,使用RDLC也是一个比较方便操作,如可以参考文章《
DevExpress的XtraReport和微软RDLC报表的使用和对比
》或者《
会员管理系统的设计和开发(2)-- RDLC报表的设计及动态加载
》进行了解。但是基于MVC方式,如何构建和展现RDLC报表呢?本文主要介绍如何在基于MVC4+EasyUI的Web开发框架上进行RDLC的集成和使用。

1、RDLC绑定数据源

RDLC的报表设计,是使用VS直接进行编辑的,因此它不管是在Web上,还是在Winform上,设计的方式都差不多,好像绑定数据源的方式有一点不同,WInform的可以选择基于,而Web的只能基于数据库连接方式构建数据绑定对象。

它们两者之间在创建数据源的时候,弹出的对话框选择界面如下所示,看起来Winform的方式选择数据源的方式很多样化。

最终,通过Web方式构建了一个数据集,并在设计视图里面设计一个用户的报表界面,并绑定它们对应的字段,具体如下所示。

在RDLC的设计界面上,它们的操作内容好像是一样的,没有什么差异,可以使用各种数学函数SUM、COUNT等,也可以使用对字段的表达式,格式样式等方式,从而方便构建出一些准确、美观的报表,这部分可以参考文中开始的那两篇引用文章,这里就不再进行细节上的赘述,因为它们是一样的。

2、在Web界面上创建一些功能按钮和实现

我们在MVC项目里面,创建并保存好RDLC报表文件到对应的Report目录上,如下所示。

然后创建一个视图,并在视图里面构建一些按钮,方便构建查询不同的报表格式功能,具体效果如下所示。

HTML代码如下所示

    <divstyle="padding:10px; border:1px solid black">
        <div>
            <ahref="@Url.Action("UserRdlcReport", new { format= "Image"})" class="easyui-linkbutton"data-options="iconCls:'icon-view'">图片输出</a>
            <ahref="@Url.Action("UserRdlcReport", new { format= "PDF"})" class="easyui-linkbutton"data-options="iconCls:'icon-view'"> PDF输出</a>
            <ahref="@Url.Action("UserRdlcReport", new { format= "Excel"})" class="easyui-linkbutton"data-options="iconCls:'icon-view'">Excel输出</a>
            <ahref="@Url.Action("UserRdlcReport", new { format= "Word"})" class="easyui-linkbutton"data-options="iconCls:'icon-view'">Word输出</a>
        </div>
    </div>
    <divid="autoUpdate"style="display: none; overflow-y: auto"class="SlideContainer">
        <tablewidth="100%"height="100%">
            <tr>
                <td>
                    <table>
                        <tr>
                            <td></td>
                            <td></td>
                        </tr>
                    </table>
                </td>
            </tr>
            <tr><td><iframeid="myReport"width="100%"height="800"></iframe></td></tr>
        </table>
    </div>

完成这些布局后,我们还需要在对应的控制器里面,对RDLC的报表进行数据绑定并呈现出来。

绑定RDLC报表,并赋值对应的数据源操作如下所示。

            LocalReport localReport = newLocalReport();
localReport.ReportPath
= Server.MapPath("~/Report/WHC.UserReport.rdlc");var dt =baseBLL.GetAll();

ReportDataSource reportDataSource
= new ReportDataSource("DataSet1", dt);
localReport.DataSources.Add(reportDataSource);

呈现的操作代码如下所示,默认我们以图片进行展现。

Warning[] warnings;string[] streams;byte[] renderedBytes;

renderedBytes
=localReport.Render(
reportType,
deviceInfo,
outmimeType,outencoding,outfileNameExtension,outstreams,outwarnings);return File(renderedBytes, (format.ToLower() == "image") ? "image/jpeg" : mimeType);

最终默认可以看到图片的报表展现效果。

当然,我们上面还有其他功能的操作,如PDF功能的展现,这个是一个不错的格式展现,每页分的很好,如果在IE里面,会独立打开PDF文件;如果是Chrome浏览器,则会在浏览器里面直接打开,比较好。

当然,Excel和Word就只能下载进行查看了,因为浏览器并不支持直接在上面进行预览查看的了,除非借助其他控件或者做法。

3、图片内容的连续输出

我们了解RDLC的话,应该知道,一般RDLC报表,它都是通过一个DeviceInfo的信息进行展现的,如下所示是一个标准的DeviceInfo对象。

            string deviceInfo =
            "<DeviceInfo>" +
            "<OutputFormat>" + deviceType + "</OutputFormat>" +
            "<PageWidth>8.5in</PageWidth>" +
            "<PageHeight>11in</PageHeight>" +
            "<MarginTop>0.5in</MarginTop>" +
            "<MarginLeft>1in</MarginLeft>" +
            "<MarginRight>1in</MarginRight>" +
            "<MarginBottom>0.5in</MarginBottom>";

但是这样的内容,如果展现图片的话,就只会展示一页的内容,一般是800的高度这样子,但是我的报表里面可能有很多记录,如何能够让它全部展现出来呢?

方法是有的,不过不是很完美,就是需要计算大概的尺寸,然后修改PageHeight的数值,让它动态的删除最大的记录,达到全部内容都可以输出看到。

为了达到这个目的,我对图片格式输出的报表,对它的高度进行了一个简单的计算,然后换成它的标准高度,这样代码如下所示。

            if(format.ToLower() == "image")
{
double inchValue = (dt.Count / 37.0) * 11;
deviceInfo
+= string.Format("<PageHeight>{0}in</PageHeight>", inchValue);
}
else{
deviceInfo
+= "<PageHeight>11in</PageHeight>";
}

最后界面代码如下所示。