MVC中灵活实现自定义查询分页之实践
注:文字写作是本人弱项,如描述有问题,请见谅!!!
前言:在开发中,经常使用查询分页,为了达到统一与复用,进行的统合实例,本实例将一步一步实现一个统合的查询分页的实现。
开发工具:VS2012
1.建立项目:
第一个是MVC4项目,第二个是一个类库
2.在类库PageSearchModel中添加引用如下:
3.要进行查询,我们添加一个查询方法枚举:QueryMethod.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace System.Web.Mvc { /// <summary> /// Html表单元素的检索方式 /// </summary> public enum QueryMethod { /// <summary> /// 等于 /// </summary> //[GlobalCode("=", OnlyAttribute = true)] Equal = 0, /// <summary> /// 小于 /// </summary> //// [GlobalCode("<", OnlyAttribute = true)] LessThan = 1, /// <summary> /// 大于 /// </summary> // [GlobalCode(">", OnlyAttribute = true)] GreaterThan = 2, /// <summary> /// 小于等于 /// </summary> // [GlobalCode("<=", OnlyAttribute = true)] LessThanOrEqual = 3, /// <summary> /// 大于等于 /// </summary> // [GlobalCode(">=", OnlyAttribute = true)] GreaterThanOrEqual = 4, /// <summary> /// Like /// </summary> // [GlobalCode("like", OnlyAttribute = true)] Like = 6, /// <summary> /// In /// </summary> // [GlobalCode("in", OnlyAttribute = true)] In = 7, /// <summary> /// 输入一个时间获取当前天的时间块操作, ToSql未实现,仅实现了IQueryable /// </summary> // [GlobalCode("between", OnlyAttribute = true)] DateBlock = 8, // [GlobalCode("<>", OnlyAttribute = true)] NotEqual = 9, // [GlobalCode("like", OnlyAttribute = true)] StartsWith = 10, // [GlobalCode("like", OnlyAttribute = true)] EndsWith = 11, /// <summary> /// 处理Like的问题 /// </summary> [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] Contains = 12, /// <summary> /// 处理In的问题 /// </summary> [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] StdIn = 13, /// <summary> /// 处理Datetime小于+23h59m59s999f的问题 /// </summary> [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] DateTimeLessThanOrEqual = 14 } }
4.添加一个排序类:QueryOrder.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace System.Web.Mvc { public class QueryOrder { public QueryOrder() { Order = OrderType.ASC; } /// <summary> /// 排序字段 /// </summary> public virtual string Field { get; set; } /// <summary> /// 排序方式 /// </summary> public virtual OrderType Order { get; set; } } public enum OrderType { ASC, DESC } }
5.添加一个组合查询条件类:ConditionItem.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Mvc; namespace System.Web.Mvc { /// <summary> /// 用于存储查询条件的单元 /// </summary> public class ConditionItem { public ConditionItem() { } public ConditionItem(string field, QueryMethod method, object val) { Field = field; Method = method; Value = val; } /// <summary> /// 字段 /// </summary> public string Field { get; set; } /// <summary> /// 查询方式,用于标记查询方式HtmlName中使用[]进行标识 /// </summary> public QueryMethod Method { get; set; } /// <summary> /// 值 /// </summary> public object Value { get; set; } /// <summary> /// 前缀,用于标记作用域,HTMLName中使用()进行标识 /// </summary> public string Prefix { get; set; } /// <summary> /// 如果使用Or组合,则此组组合为一个Or序列 /// </summary> public string OrGroup { get; set; } } }
6.添加一个表格的列类:PageColum.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace System.Web.Mvc { /// <summary> /// 列 /// </summary> public class PageColum { public PageColum() { Id = Guid.NewGuid().ToString(); Sort = false; } /// <summary> /// 编号 /// </summary> public string Id { get; set; } /// <summary> /// 字段 /// </summary> public string Field { get; set; } /// <summary> /// 列头名 /// </summary> public string Header { get; set; } /// <summary> /// 排序 DESC为true /// </summary> public bool Sort { get; set; } /// <summary> /// 列样式 /// </summary> public string Style { get; set; } } /// <summary> /// 列 /// </summary> public class PageColum<T> : PageColum { public Func<T, object> Format { get; set; } } }
7.添加一个表格的行类:PageRow.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace System.Web.Mvc { /// <summary> /// 行 /// </summary> public class PageRow { public PageRow() { RowData = new List<RowItem>(); } // <summary> /// 行数据 /// </summary> public IList<RowItem> RowData { get; set; } /// <summary> /// 单行数据对象的主键字段名 /// </summary> public string SourcePrimaryKey { get; set; } /// <summary> /// 行样式 /// </summary> public string Style { get; set; } } /// <summary> /// 行中单列数据 /// </summary> public class RowItem { /// <summary> /// 对应列编号 /// </summary> public string ColumId { get; set; } /// <summary> /// 是否是字段列 /// </summary> public bool CheckFieldColum { get; set; } /// <summary> /// 值 /// </summary> public object Vaule { get; set; } } }
8.添加一个查询分页类:PageModel.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Web; using System.Web.WebPages; namespace System.Web.Mvc { /// <summary> /// 分页模型 /// </summary> public class PageModel { public PageModel() { this.PageIndex = 1; this.PageSize = 15; SearchQuery = new List<ConditionItem>(); Id = Guid.NewGuid().ToString().Replace(@"/","").Replace(@"\","").Replace("-", "_"); } /// <summary> /// 页的唯一标识 /// </summary> public virtual string Id { get; set; } /// <summary> /// 页码从1开始 /// </summary> public virtual int PageIndex { get; set; } /// <summary> /// 每页显示数量 /// </summary> public virtual int PageSize { get; set; } /// <summary> /// 页总数 /// </summary> public virtual long PageTotal { get { #region if (DataTotal == 0) { return 0; } else if (DataTotal <= PageSize) { return 1; } else { var z = DataTotal / PageSize; var y = DataTotal % PageSize; if (y != 0) { return z + 1; } else { return z; } } #endregion } } /// <summary> /// 数据总数 /// </summary> public virtual long DataTotal { get; set; } /// <summary> /// 查询条件 /// </summary> public virtual List<ConditionItem> SearchQuery { get; set; } /// <summary> /// 排序 /// </summary> public virtual QueryOrder Order { get; set; } /// <summary> /// 是否全选 /// </summary> public bool SelectAll { get; set; } /// <summary> /// 选择的查询集合 /// </summary> public IList<string> SelectPrimaryKeys { get; set; } /// <summary> /// 判断查询字段是存在 /// </summary> /// <param name="expr"></param> /// <returns></returns> public bool CheckSearchName<T>(Expression<Func<T, object>> expr) { var field= expr.Body.ToString().Split('.').Last(); if (SearchQuery.Where(m => m.Field == field).Count() > 0) return true; else return false; } /// <summary> /// 查询字段值 /// </summary> /// <param name="expr"></param> /// <returns></returns> public object SearchValue<T>(Expression<Func<T, object>> expr) { var field = expr.Body.ToString().Split('.').Last(); var data = this.SearchQuery.Where(m => m.Field == field); if (data.Count() > 0) { return data.First().Value; } return ""; } /// <summary> /// 设置当前分页对象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="data"></param> /// <param name="dataTotal"></param> /// <returns></returns> public PageModel<T> Record<T>(IEnumerable<T> data, long dataTotal = -1) where T : class { var model = new PageModel<T>(data, dataTotal); model.PageIndex = this.PageIndex; model.PageSize = this.PageSize; model.Order = this.Order; model.SearchQuery = this.SearchQuery; return model; } } /// <summary> /// 分页模型 /// </summary> public class PageModel<T> : PageModel,IHtmlString where T : class//,IHtmlString { public PageModel(IEnumerable<T> data, Int64 dataTotal = -1) : base() { #region 设置数据总数 if (data != null) DataSource = data; else DataSource = new List<T>(); if (dataTotal == -1) { if (data != null) { DataTotal = data.Count(); } else { DataTotal = 0; } } else { DataTotal = dataTotal; } #endregion this.TableClassName = "baseui-table"; Colums = new List<PageColum<T>>(); } /// <summary> /// 数据源 /// </summary> public virtual IEnumerable<T> DataSource { get; set; } /// <summary> /// 数据列 /// </summary> private IList<PageColum<T>> Colums { get; set; } /// <summary> /// 数据的主键字段名 /// </summary> private string SourcePrimaryKey { get; set; } /// <summary> /// 是否显示选择框 /// </summary> private bool ShowCheckBox { get; set; }//显示选择框 /// <summary> /// 列样式类名 /// </summary> private string TableClassName { get; set; } /// <summary> /// 提交的表单ID /// </summary> private string SearchFormId { get; set; } /// <summary> /// 要查询的form表单ID /// </summary> /// <param name="id"></param> /// <returns></returns> public PageModel<T> SetSearchFormId(string id) { this.SearchFormId = id; return this; } /// <summary> /// 是否显示选择框 /// </summary> /// <param name="show"></param> /// <returns></returns> public PageModel<T> SetShowCheckBox(bool show = false) { this.ShowCheckBox = show; return this; } /// <summary> /// 查询字段 /// </summary> /// <param name="expr"></param> /// <returns></returns> public string SearchName(Expression<Func<T, object>> expr) { return expr.Body.ToString().Split('.').Last(); } /// <summary> /// 查询字段值 /// </summary> /// <param name="expr"></param> /// <returns></returns> public object SearchValue(Expression<Func<T, object>> expr) { var data = this.SearchQuery.Where(m => m.Field == SearchName(expr)); if (data.Count() > 0) { return data.First().Value; } return ""; } /// <summary> /// 设置数据源的每一行的主键字段 /// </summary> /// <param name="expr"></param> /// <returns></returns> public PageModel<T> SetSourceKey(Expression<Func<T, object>> expr) { this.SourcePrimaryKey = expr.Body.ToString().Split('.').Last(); return this; } /// <summary> /// 设置表的样式类 /// </summary> /// <param name="className"></param> /// <returns></returns> public PageModel<T> SetClass(string className) { this.TableClassName = className; return this; } /// <summary> /// 设置显示列 /// </summary> /// <param name="expr"></param> /// <param name="header"></param> /// <param name="sort"></param> /// <param name="style"></param> /// <returns></returns> public PageModel<T> ColumFor(Expression<Func<T, object>> expr, string header = "", bool sort = false, string style = "") { var exprBody = expr.Body.ToString(); if (exprBody.Contains("Convert")) { exprBody = exprBody.Replace("Convert", "").Replace("(", "").Replace(")", ""); } var field = exprBody.Split('.').Last();//ExpressionHelper.GetExpressionText(expr); if (string.IsNullOrEmpty(header)) { try { var metadata = ModelMetadata.FromLambdaExpression<T, object>(expr, new ViewDataDictionary<T>()); string resolvedDisplayName = metadata.DisplayName ?? metadata.PropertyName ?? field.Split('.').Last(); header = HttpUtility.HtmlEncode(resolvedDisplayName); } catch//处理比如datetime类型的属性 { try { //ModelMetadataProvider provider = ModelMetadataProviders.Current; //ModelMetadata containerMetadata = new ModelMetadata(provider, null, () => null, typeof(T), null); //var metadata = containerMetadata.Properties.FirstOrDefault(m => m.PropertyName == field); var metadata = GetModelMetadata<T>(field); string resolvedDisplayName = metadata.DisplayName ?? metadata.PropertyName ?? field.Split('.').Last(); header = HttpUtility.HtmlEncode(resolvedDisplayName); } catch { } } } this.Colums.Add(new PageColum<T>() { Field = field, Header = header, Style = style, Sort = sort }); return this; } /// <summary> /// 列 /// </summary> /// <param name="header"></param> /// <param name="func"></param> /// <param name="style"></param> /// <returns></returns> public PageModel<T> Colum(string header, Func<T, object> func, bool sort = false, string style = "") { this.Colums.Add(new PageColum<T>() { Field = "", Header = header, Style = style, Format = func, Sort = sort }); return this; } public MvcHtmlString ToMvcHtmlString() { var Model = this; var html = new StringBuilder(); if (Model.Order != null && Model.Order.Field != "") { html.Append(string.Format("<input name=\"[PageModel_Order]\" type=\"hidden\" value=\"{0}\">", Model.Order.Field + "|" + Model.Order.Order.ToString())); } else { html.Append(string.Format("<input name=\"[PageModel_Order]\" type=\"hidden\" value=\"{0}\">", "")); } html.Append(string.Format("<input name=\"[PageModel_PageIndex]\" type=\"hidden\" value=\"{0}\">", 1)); html.Append(string.Format("<input name=\"[PageModel_PageSize]\" type=\"hidden\" value=\"{0}\">", Model.PageSize.ToString())); html.Append(string.Format("<input name=\"[PageModel_CheckSearch]\" type=\"hidden\" value=\"{0}\">", "1")); html.Append(string.Format("<input name=\"[PageModel_SelectIds]\" type=\"hidden\" value=\"{0}\">", "")); html.Append(string.Format("<input name=\"[PageModel_PageTotal]\" type=\"hidden\" value=\"{0}\">", Model.PageTotal)); #region 表 var columCount = 0; html.Append(string.Format("<table class=\"{0}\">",this.TableClassName)); html.Append("<thead>"); html.Append("<tr>"); //html.Append("<th>[]</th>");//列头 if (Colums != null) { columCount = Colums.Count; if (this.ShowCheckBox) { columCount += 1; html.Append("<th style=\"width: 40px;\" ><input class=\"baseui-checkbox\" onchange=\"PageModelCheck('pageModelCheck_All')\" id=\"pageModelCheck_All\" name=\"pageModelCheck_All\" type=\"checkbox\" value=\"true\">选择</th>"); } foreach (var colum in Colums) { if (colum.Sort) { html.Append(string.Format("<th ><a href=\"javascript:;\" onclick=\"SearchPageModelOrder('{2}','{0}');\">{1}</a></th>" , colum.Field , colum.Header , this.SearchFormId)); } else { html.Append(string.Format("<th ><a href=\"javascript:;\">{0}</a></th>", colum.Header)); } } } html.Append("</tr>"); html.Append("</thead>"); html.Append("<tbody>"); if (Model != null && Model.DataSource.Count() > 0) { //html.Append("<td>[]</td>");//列 var rows = this.CreateRows(); foreach (var item in rows) { html.Append("<tr>"); if (this.ShowCheckBox) { html.Append(string.Format("<td><input class=\"baseui-checkbox\" onchange=\"PageModelCheck('pageModelCheck_{0}')\" id=\"pageModelCheck_{0}\" name=\"pageModelCheck_{0}\" type=\"checkbox\" value=\"true\"></td>", item.SourcePrimaryKey)); } foreach (var colum in item.RowData) { html.Append(string.Format("<td>{0}</td>", colum.Vaule)); } html.Append("</tr>"); } html.Append("</tbody>"); html.Append("<tfoot>"); html.Append("<tr>"); html.Append(string.Format("<td colspan=\"{0}\">", columCount)); html.Append("<div class=\"baseui-paging\">"); if (Model.PageIndex == 1) { html.Append(" <a href=\"javascript:;\" class=\"baseui-paging-prev\">"); html.Append("<i class=\"iconfont\" ></i> 第一页"); html.Append("</a>"); } else { html.Append(string.Format(" <a href=\"javascript:;\" onclick=\"SearchPageModelPage('{0}','1');\" class=\"baseui-paging-prev\">", this.SearchFormId)); html.Append("<i class=\"iconfont\" ></i> 第一页"); html.Append("</a>"); } var pNumber = 10; var start = GetStartNumber(Model.PageIndex, Model.PageTotal, pNumber); for (int i = 0; i < pNumber; i++) { if (start + i <= Model.PageTotal) { if (start + i == Model.PageIndex) { html.Append(string.Format("<a href=\"javascript:;\" class=\"baseui-paging-item baseui-paging-current\">{0}</a>", start + i)); } else { html.Append(string.Format("<a href=\"javascript:;\" onclick=\"SearchPageModelPage('{1}','{0}');\" class=\"baseui-paging-item\">{0}</a>", start + i, this.SearchFormId)); } } } if (Model.PageIndex == Model.PageTotal || Model.PageTotal == 0) { html.Append("<a href=\"javascript:;\" class=\"baseui-paging-next\">最后一页 <i class=\"iconfont\" ></i></a>"); } else { html.Append(string.Format("<a href=\"javascript:;\" onclick=\"SearchPageModelPage('{1}','{0}');\" class=\"baseui-paging-next\">最后一页 <i class=\"iconfont\"></i></a>", Model.PageTotal, this.SearchFormId)); } html.Append(string.Format("<span class=\"baseui-paging-info\"><span class=\"baseui-paging-bold\">{0}/{1}</span>页</span>", Model.PageIndex, Model.PageTotal)); html.Append("<span class=\"baseui-paging-which\">"); html.Append(string.Format("<input name=\"[psome_name]\" value=\"{0}\" type=\"text\">", Model.PageIndex)); html.Append("</span>"); html.Append(string.Format(" <a class=\"baseui-paging-info baseui-paging-goto\" href=\"javascript:;\" onclick=\"SearchPageModelPageJmp('{0}')\">跳转</a>", this.SearchFormId)); html.Append(" </div>"); html.Append(" </td>"); html.Append("</tr>"); html.Append("</tfoot>"); html.Append("</table>"); } else { html.Append("<tr>"); html.Append(string.Format("<td colspan=\"{0}\">暂无数据</td>", columCount)); html.Append("</tr>"); html.Append("</tbody>"); html.Append("</table>"); } #endregion html.Append("<script> function SearchPageModelOrder(searchFormId, value) { var oldValue = $(\"input[name='[PageModel_Order]']\").val(); var newValue = \"\"; if (oldValue == \"\" || oldValue == value + \"|Desc\") $(\"input[name='[PageModel_Order]']\").val(value + \"|Asc\"); else $(\"input[name='[PageModel_Order]']\").val(value + \"|Desc\"); $(\"input[name='[PageModel_CheckSearch]']\").val(\"0\");$(\"#\" + searchFormId).submit();}function SearchPageModelPage(searchFormId, value) {$(\"input[name='[PageModel_PageIndex]']\").val(value);$(\"input[name='[PageModel_CheckSearch]']\").val(\"0\");$(\"#\" + searchFormId).submit();} function SearchPageModelPageJmp(searchFormId) {var pindex = $(\"input[name='[psome_name]']\").val();$(\"input[name='[PageModel_PageIndex]']\").val(pindex);$(\"#\" + searchFormId).submit();}"); string js = "function PageModelCheck(v) {var id = v.split('_')[1]; var oldValue=$(\"input[name='[PageModel_SelectIds]']\").val(); if ($(\"#\" + v).is(\":checked\")) { if (id == \"All\") { $(\"input:checkbox\").each(function (i, ele) { var cid = $(ele).attr(\"id\"); if (cid.indexOf(\"pageModelCheck\") >= 0) { $(ele).attr(\"checked\", true); } }); $(\"input[name='[PageModel_SelectIds]']\").val(id); } else { if (oldValue.indexOf(id) < 0) { var newValue = oldValue + \"|\" + id; $(\"input[name='[PageModel_SelectIds]']\").val(newValue); } } } else { if (id == \"All\") { $(\"input:checkbox\").each(function (i, ele) { var cid = $(ele).attr(\"id\"); if (cid.indexOf(\"pageModelCheck\") >= 0) { $(ele).attr(\"checked\", false); } }); $(\"input[name='[PageModel_SelectIds]']\").val(\"\"); } else { if (oldValue.indexOf(id) >= 0) { var newValue = oldValue.replace(\"|\"+id,\"\"); $(\"input[name='[PageModel_SelectIds]']\").val(newValue); } } } }"; html.Append(js); html.Append(" function PageModeSelectIds() { var ids = $(\"input[name='[PageModel_SelectIds]']\").val(); return ids;}"); html.Append(" </script>"); return MvcHtmlString.Create(html.ToString()); } private List<PageRow> CreateRows() { var rows = new List<PageRow>(); //ModelMetadataProvider provider = ModelMetadataProviders.Current; //ModelMetadata containerMetadata = new ModelMetadata(provider, null, () => null, typeof(T), null); //var properties = containerMetadata.Properties.Select(m => m.PropertyName); if (this.DataSource != null && this.DataSource.Count() > 0 && this.Colums != null && this.Colums.Count > 0) { foreach (var data in this.DataSource) { var row = new PageRow(); if (!string.IsNullOrEmpty(this.SourcePrimaryKey)) { var keyValue = data.GetType().GetProperty(this.SourcePrimaryKey).GetValue(data, null); row.SourcePrimaryKey = keyValue == null ? Guid.NewGuid().ToString() : keyValue.ToString(); } else { row.SourcePrimaryKey = Guid.NewGuid().ToString(); } foreach (var colum in this.Colums) { if (!string.IsNullOrEmpty(colum.Field)) { var colValue = data.GetType().GetProperty(colum.Field).GetValue(data, null); row.RowData.Add(new RowItem() { ColumId = colum.Id, Vaule = colValue, CheckFieldColum = true}); } else { var html = Format(colum.Format, data); row.RowData.Add(new RowItem() { ColumId = colum.Id, Vaule = HttpUtility.HtmlEncode(html), CheckFieldColum = false }); } } rows.Add(row); } } return rows; } /// <summary> /// 执行委托 /// </summary> /// <param name="format">lambda表达示</param> /// <param name="arg">委托参数</param> /// <returns></returns> private HelperResult Format(Func<T, object> format, dynamic arg) { var result = format.Invoke(arg); return new HelperResult(tw => { var helper = result as HelperResult; if (helper != null) { helper.WriteTo(tw); return; } IHtmlString htmlString = result as IHtmlString; if (htmlString != null) { tw.Write(htmlString); return; } if (result != null) { tw.Write(HttpUtility.HtmlEncode(result)); } }); } /// <summary> /// 获得一个数左右多少个的起始数 /// </summary> /// <param name="helper"></param> /// <param name="currentNumber">当前数</param> /// <param name="maxNumber">最大数</param> /// <param name="showCount">一共多少个</param> /// <returns></returns> private Int64 GetStartNumber(Int64 currentNumber, Int64 maxNumber, int showCount) { var arr = new List<Int64>(); var pAvg = showCount / 2;//左右显示个数 for (int i = 1; i <= pAvg; i++) { if (currentNumber - i > 0) { arr.Add(currentNumber - i); } if (currentNumber + i <= maxNumber) { arr.Add(currentNumber + i); } } arr.Add(currentNumber); if (arr.Count < 10) { var le = showCount - arr.Count; var min = arr.Min(); var max = arr.Max(); for (int i = 1; i <= le; i++) { if (min == 1 && max + 1 <= maxNumber) { arr.Add(max + 1); } if (max == maxNumber && min - 1 >= 1) { arr.Add(min - 1); } } } return arr.Min(); } private ModelMetadata GetModelMetadata<T>(string PropertyName) { ModelMetadataProvider provider = ModelMetadataProviders.Current; ModelMetadata containerMetadata = new ModelMetadata(provider, null, () => null, typeof(T), null); var metadata = containerMetadata.Properties.FirstOrDefault(m => m.PropertyName == PropertyName); return metadata; } public string ToHtmlString() { return this.ToMvcHtmlString().ToHtmlString(); } } }
9.添加一个设置对Html的替换规则类:MvcHtmlWrapper.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; using System.Text; using System.Web; using System.Web.Mvc; namespace System.Web.Mvc { /// <summary> /// MvcHtmlString包装器 /// 用于设置对Html的替换规则并在输出时统一处理显示Html /// </summary> public class MvcHtmlWrapper : IHtmlString { /// <summary> /// 构建一个MvcHtmlWrapper,如果是MvcHtmlWrapper则直接返回, /// 如果是是其它类型则构造MvcHtmlWrapper后返回 /// </summary> /// <param name="str">IHtmlString类型,实现了ToHtmlString接口的类型</param> /// <returns></returns> public static MvcHtmlWrapper Create(IHtmlString str) { Contract.Requires(str != null); if (str is MvcHtmlWrapper) return str as MvcHtmlWrapper; if (str is MvcHtmlString) return new MvcHtmlWrapper(str); Contract.Assert(false); return null; } IHtmlString HtmlStringInterface { get; set; } private string _htmlString; /// <summary> /// 获取MvcHtmlString所生成的Html字符串 /// </summary> public string HtmlString { get { return _htmlString ?? (_htmlString = HtmlStringInterface.ToHtmlString()); } } /// <summary> /// 用于替换的Dict /// </summary> public List<Tuple<string, string>> ReplaceDict { get; set; } /// <summary> /// 构造MvcHtmlString包装器 /// </summary> /// <param name="str">MvcHtmlString的实例,不允许为空</param> MvcHtmlWrapper(IHtmlString str) { Contract.Requires(str != null); HtmlStringInterface = str; ReplaceDict = new List<Tuple<string, string>>(); } /// <summary> /// 对ToHtmlString进行了重写, 输出HtmlString的内容,并按替换规则进行了替换 /// </summary> /// <returns></returns> public string ToHtmlString() { return ToString(); } /// <summary> /// 对ToString进行了重写, 输出HtmlString的内容,并按替换规则进行了替换 /// </summary> /// <returns></returns> public override string ToString() { var sb = new StringBuilder(HtmlString); foreach (var item in ReplaceDict) { if (!string.IsNullOrEmpty(item.Item1)) { sb.Replace(item.Item1, item.Item2); } } return sb.ToString(); } /// <summary> /// 添加替换原则 /// </summary> /// <param name="item1">被替换的字符串</param> /// <param name="item2">替换为的字符串</param> internal void Add(string item1, string item2) { ReplaceDict.Add(Tuple.Create(item1, item2)); } } }
10.添加一个MVC Html的扩展类:MvcHtmlStringExtension.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.Contracts; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Web; using System.Web.Mvc; namespace System.Web.Mvc { [EditorBrowsable(EditorBrowsableState.Never)] public static class MvcHtmlStringExtension { /// <summary> /// 扩展分页查询表 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="helper"></param> /// <param name="SearchFormId">要查询的form表单ID</param> /// <returns></returns> public static PageModel<T> PageTableFor<T>(this HtmlHelper<PageModel<T>> helper, string SearchFormId) where T : class { var model = helper.ViewData.Model; model = model.SetSearchFormId(SearchFormId); return model; } #region ForSearch /// <summary> /// 为当前表单元素添加搜索条件 /// </summary> /// <param name="str"></param> /// <param name="method">搜索方法</param> /// <param name="prefix">前缀</param> /// <param name="hasId">是否显示Id,默认false</param> /// <param name="orGroup">如果想要支援Or,请设置一个Or分组</param> /// <returns></returns> public static MvcHtmlWrapper ForSearch(this IHtmlString str, QueryMethod? method, string prefix = "", bool hasId = false, string orGroup = "") { var wrapper = MvcHtmlWrapper.Create(str); Contract.Assert(null != wrapper); if (!method.HasValue) return wrapper; var html = wrapper.HtmlString; #region 如果是CheckBox,则去掉hidden if (html.Contains("type=\"checkbox\"")) { var checkMatch = Regex.Match(html, "<input name=\"[^\"]+\" type=\"hidden\" [^>]+ />"); if (checkMatch.Success) { wrapper.Add(checkMatch.Groups[0].Value, string.Empty); } } #endregion #region 替换掉Name var match = Regex.Match(html, "name=\"(?<name>[^\"]+)\""); var strInsert = ""; if (!string.IsNullOrWhiteSpace(prefix)) { strInsert += string.Format("({0})", prefix); } if (!string.IsNullOrWhiteSpace(orGroup)) { strInsert += string.Format("{{{0}}}", orGroup); } if (match.Success) { wrapper.Add(match.Groups[0].Value, string.Format("name=\"[{1}]{2}{0}\"", match.Groups[1].Value, method, strInsert)); } #endregion return wrapper; } #endregion } }
11.添加一个模型映射类:SearchModelBinder.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Mvc; namespace System.Web.Mvc { /// <summary> /// 对SearchModel做为Action参数的绑定 /// </summary> public class SearchModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var model = (PageModel)(bindingContext.Model ?? new PageModel()); var dict = controllerContext.HttpContext.Request.Params; var keys = dict.AllKeys.Where(c => c.StartsWith("["));//我们认为只有[开头的为需要处理的 if (keys.Count() != 0) { foreach (var key in keys) { if (!key.StartsWith("[")) continue; var val = dict[key]; //处理无值的情况 if (string.IsNullOrEmpty(val)) continue; if (key == "[PageModel_Order]")//排序 { var arr = val.Split('|'); if (arr.Length == 2) { model.Order = new QueryOrder() { Field = arr[0], Order = (OrderType)Enum.Parse(typeof(OrderType), arr[1]) }; } continue; } if (key == "[PageModel_PageIndex]")//页码 { try { var pindex = int.Parse(val); if (pindex > 1) model.PageIndex = pindex; else model.PageIndex = 1; if (keys.Contains("[PageModel_PageTotal]")) { var pt = int.Parse(dict["[PageModel_PageTotal]"]); if (pindex > pt) { model.PageIndex = 1; } } } catch { model.PageIndex = 1; } continue; } if (key == "[PageModel_PageTotal]") { continue; } if (key == "[PageModel_PageSize]")//每页显示数量 { try { var pSize = int.Parse(val); if (pSize > 0) model.PageSize = pSize; else model.PageSize = 20; } catch { model.PageSize = 20; } continue; } if (key == "[PageModel_CheckSearch]") { if (val == "1") { //model.che = 1; } continue; } if (key == "[PageModel_SelectIds]") { if (val == "All") { model.SelectAll = true; } else { model.SelectAll = false; model.SelectPrimaryKeys = val.Split('|').Where(m => m != "").ToList(); } continue; } if (key == "[psome_name]") { continue; } AddSearchItem(model, key, val); } } return model; } /// <summary> /// 将一组key=value添加入PageModel.SearchQuery /// </summary> /// <param name="model">PageModel</param> /// <param name="key">当前项的HtmlName</param> /// <param name="val">当前项的值</param> public static void AddSearchItem(PageModel model, string key, string val) { string field = "", prefix = "", orGroup = "", method = ""; var keywords = key.Split(']', ')', '}'); //将Html中的name分割为我们想要的几个部分 foreach (var keyword in keywords) { if (Char.IsLetterOrDigit(keyword[0])) field = keyword; var last = keyword.Substring(1); if (keyword[0] == '(') prefix = last; if (keyword[0] == '[') method = last; if (keyword[0] == '{') orGroup = last; } if (string.IsNullOrEmpty(method)) return; if (!string.IsNullOrEmpty(field)) { var item = new ConditionItem { Field = field, Value = val.Trim(), Prefix = prefix, OrGroup = orGroup, Method = (QueryMethod)Enum.Parse(typeof(QueryMethod), method) }; model.SearchQuery.Add(item); } } } }
到此类库封闭完毕。我们将WEB引用此类库。
12.在Global.asax中添加:
ModelBinders.Binders.Add(typeof(PageModel), new SearchModelBinder());
13.现在我们WEB的Models中添加一个UserModel.cs进行实例展示:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Web; namespace MvcApplication.Models { public class UserModel { [Display(Name = "编号")] public virtual string Id { get; set; } [Display(Name = "姓名")] public virtual string Name { get; set; } /// <summary> /// true:男 false:女 /// </summary> [Display(Name = "性别")] public virtual bool IsSex { get; set; } [Display(Name = "生日")] public virtual DateTime Birthday { get; set; } [Display(Name="性别")] public string SexName { get { return this.IsSex ? "男" : "女"; } } } }
14.修改HomeController:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using MvcApplication.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcApplication.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult Table(PageModel model) { var data = CreateData(); var dCount = data.Count; data = data.Skip((model.PageIndex - 1) * model.PageSize).Take(model.PageSize).ToList(); return PartialView(model.Record<UserModel>(data, dCount)); } private IList<UserModel> CreateData() { var list = new List<UserModel>(); for (int i = 0; i < 100; i++) { list.Add(new UserModel() { Id=i.ToString(), Name="姓名"+i.ToString(), IsSex=true, Birthday=DateTime.Now }); } return list; } public ActionResult About() { ViewBag.Message = "你的应用程序说明页。"; return View(); } public ActionResult Contact() { ViewBag.Message = "你的联系方式页。"; return View(); } } }
15.修改Index.cshtml:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@{ ViewBag.Title = "主页"; } @section featured { } <div id="tb001"> @Html.Action("Table") </div>
16.添加Table视图:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@model PageModel<MvcApplication.Models.UserModel> @{ Layout = null; var ajaxOption = new AjaxOptions() { HttpMethod = "Post", UpdateTargetId = "tb001", OnBegin = "$('#pageMode_tableConetnt').mask();", OnComplete = "$('#pageMode_tableConetnt').unmask();", InsertionMode = InsertionMode.Replace }; } @using (Ajax.BeginForm("Table", "Home", null, ajaxOption, new { @id = "PageModel_Form" })) { <div> <div class="baseui-box"> <div class="baseui-box-head"> <h3 class="baseui-box-head-title">查询</h3> <span class="baseui-box-head-text">Search</span> </div> <div class="baseui-box-container"> <div class="baseui-box-content"> 姓名: @Html.TextBox(Model.SearchName(m => m.Name), Model.SearchValue(m => m.Name), new { @class = "baseui-input" }).ForSearch(QueryMethod.Like) <input type="submit" value="查询" class="baseui-button baseui-button-sorange" /> </div> </div> </div> <br /> <div class="baseui-box"> <div class="baseui-box-head"> <a href="@Url.Action("Add")" data-dialog-title="添加产品类型" data-dialog="true"> <i class="iconfont"></i> 添加 </a> </div> <div class="baseui-box-container"> <div class="baseui-box-content" style="padding: 0px !important;"> <div id="pageMode_tableConetnt"> @(Html.PageTableFor("PageModel_Form") .SetClass("baseui-table") .SetShowCheckBox(false) .SetSourceKey(m => m.Id) .ColumFor(m => m.Name) .ColumFor(m=>m.SexName) .Colum("生日",m=>m.Birthday.ToShortDateString()) .Colum("操作", @<text> @Html.ActionLink("修改", "Edit", new { id = @item.Id } ,new { data_dialog = "true", data_dialog_title = "修改产品类型" }) | @Ajax.ActionLink("删除", "Delete", new { id = @item.Id }, ajaxOption , new { confirm_show = "true", confirm_tile = "提示", confirm_content = "是否删除?", confirm_height = 210 }) </text>) ) </div> </div> </div> </div> </div> }
现在,我们看看运行效果:
当我们在姓名查询框中输入:张三
现在添加断点:
这样处理后,自己再进行处理封装是不是很方便呢。
有些功能尚未实现,请自行修改
本实例到此结束,如有不懂的地方请留言,如果大家觉得好请支持留言,如果有更好的处理方法请留言告知,不胜感激,在此谢谢了!!!