Last active
November 13, 2019 03:08
-
-
Save dinowang/6302408 to your computer and use it in GitHub Desktop.
ASP.NET MVC QueryOption<T> implementation. depend on PagedList, PagedList.Mvc.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public enum Order | |
{ | |
Ascending, | |
Descending | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using PagedList.Mvc; | |
public class PagingOptions | |
{ | |
public static PagedListRenderOptions Standard | |
{ | |
get | |
{ | |
var options = new PagedListRenderOptions | |
{ | |
DisplayLinkToFirstPage = PagedListDisplayMode.Always, | |
DisplayLinkToPreviousPage = PagedListDisplayMode.Always, | |
LinkToPreviousPageFormat = "上一頁", | |
DisplayLinkToNextPage = PagedListDisplayMode.Always, | |
LinkToNextPageFormat = "下一頁", | |
DisplayLinkToLastPage = PagedListDisplayMode.Always | |
}; | |
return options; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using PagedList; | |
public class QueryOption<T> | |
{ | |
public string Keyword { get; set; } | |
public int Page { get; set; } | |
public int PageSize { get; set; } | |
public string Column { get; set; } | |
public Order Order { get; set; } | |
public IPagedList<T> Result { get; set; } | |
public QueryOption() | |
{ | |
Page = 1; | |
PageSize = 20; | |
} | |
public void SetSource(IEnumerable<T> source) | |
{ | |
SetSource(source.AsQueryable()); | |
} | |
public void SetSource(IQueryable<T> source) | |
{ | |
if (string.IsNullOrEmpty(Column)) | |
{ | |
Column = typeof (T).GetProperties().First().Name; | |
} | |
var param = Expression.Parameter(typeof (T)); | |
Expression parent = param; | |
foreach (var column in Column.Split(new[] { '.' })) | |
{ | |
parent = Expression.Property(parent, column); | |
} | |
dynamic keySelector = Expression.Lambda(parent, param); | |
IOrderedQueryable<T> query = null; | |
if (Order == Order.Ascending) | |
{ | |
query = Queryable.OrderBy(source, keySelector); | |
} | |
else | |
{ | |
query = Queryable.OrderByDescending(source, keySelector); | |
} | |
Result = query.ToPagedList(Page, PageSize); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Web.Mvc; | |
using System.Web.Routing; | |
using Workshop.ViewModels; | |
public static class QueryOptionHtmlExtensions | |
{ | |
public static MvcHtmlString SortableFor<TEntity, TProperty>( | |
this HtmlHelper<QueryOption<TEntity>> htmlHelper, | |
Expression<Func<TEntity, TProperty>> expression, | |
string tagName, | |
string text = null, | |
object htmlAttributes = null) | |
{ | |
var column = GetFullPropertyName(expression); | |
var tag = new TagBuilder(tagName); | |
tag.AddCssClass("sortable"); | |
tag.Attributes["data-column"] = column; | |
if (text == null) | |
{ | |
var memberAccess = expression.Body as MemberExpression; | |
text = memberAccess.Member.Name; | |
var displayAttr = (DisplayNameAttribute)memberAccess.Member.GetCustomAttributes(typeof (DisplayNameAttribute), true).FirstOrDefault(); | |
if (displayAttr != null) | |
{ | |
text = displayAttr.DisplayName; | |
} | |
} | |
tag.SetInnerText(text); | |
var queryOption = htmlHelper.ViewData.Model; | |
if (queryOption.Column == column) | |
{ | |
var order = queryOption.Order; | |
tag.Attributes["data-direction"] = order.ToString(); | |
var icon = new TagBuilder("i"); | |
icon.AddCssClass("icon"); | |
switch (order) | |
{ | |
case Order.Ascending: | |
icon.AddCssClass("icon-chevron-up"); | |
break; | |
case Order.Descending: | |
icon.AddCssClass("icon-chevron-down"); | |
break; | |
} | |
tag.InnerHtml += " " + icon.ToString(); | |
} | |
if (htmlAttributes != null) | |
{ | |
var attributes = new RouteValueDictionary(htmlAttributes); | |
tag.MergeAttributes(attributes); | |
} | |
return new MvcHtmlString(tag.ToString()); | |
} | |
// code adjusted to prevent horizontal overflow | |
static string GetFullPropertyName<TEntity, TProperty>( | |
Expression<Func<TEntity, TProperty>> expression) | |
{ | |
MemberExpression memberExpression; | |
if (!TryFindMemberExpression(expression.Body, out memberExpression)) | |
{ | |
return string.Empty; | |
} | |
var memberNames = new Stack<string>(); | |
do | |
{ | |
memberNames.Push(memberExpression.Member.Name); | |
} | |
while (TryFindMemberExpression(memberExpression.Expression, out memberExpression)); | |
return string.Join(".", memberNames.ToArray()); | |
} | |
// code adjusted to prevent horizontal overflow | |
private static bool TryFindMemberExpression( | |
Expression expression, | |
out MemberExpression memberExpression) | |
{ | |
memberExpression = expression as MemberExpression; | |
if (memberExpression != null) | |
{ | |
// heyo! that was easy enough | |
return true; | |
} | |
// if the compiler created an automatic conversion, | |
// it'll look something like... | |
// obj => Convert(obj.Property) [e.g., int -> object] | |
// OR: | |
// obj => ConvertChecked(obj.Property) [e.g., int -> long] | |
// ...which are the cases checked in IsConversion | |
if (IsConversion(expression) && expression is UnaryExpression) | |
{ | |
memberExpression = ((UnaryExpression)expression).Operand as MemberExpression; | |
if (memberExpression != null) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
private static bool IsConversion(Expression exp) | |
{ | |
return ( | |
exp.NodeType == ExpressionType.Convert || | |
exp.NodeType == ExpressionType.ConvertChecked | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; | |
$(function () { | |
// jQuery Selector (DOM 關聯) 需根據不同的 View layout 調整 | |
$("#wrap .form-search") | |
.each(function (i, el) { | |
var $form = $(this), | |
$submit = $form.find("[type=submit]"), | |
$toolbar = $form.parent(".btn-toolbar"), | |
$table = $toolbar.next().find("table:first"), | |
$sortable = $table.find("tr:first").find(".sortable"), | |
$pager = $toolbar.next().find(".pagination"); | |
$sortable.click(function () { | |
var $this = $(this), | |
$icon = $this.find("i.icon"), | |
column = $this.data("column"), | |
order = $this.data("direction"); | |
switch (order) { | |
case "Ascending": | |
nextSort(column, "Descending"); | |
$icon.attr("class", "icon icon-chevron-down"); | |
break; | |
case "Descending": | |
nextSort(null, null); | |
$icon.removeClass("icon"); | |
break; | |
default: | |
nextSort(column, "Ascending"); | |
$this.append(" <i class='icon icon-chevron-up' />"); | |
break; | |
} | |
return false; | |
}); | |
var nextSort = function (column, order) { | |
$form.find("[name=Column]").val(column); | |
$form.find("[name=Order]").val(order); | |
$form.trigger("submit"); | |
}; | |
$submit.click(function () { | |
$form.find("[name=Page]").val(1); | |
$form.trigger("submit"); | |
}); | |
$pager.on("click", "a", function (evt) { | |
var $page = $form.find("[name=Page]"), | |
page = parseInt(this.href.match(/(\d+)$/)[1]); | |
if (isNaN(page)) | |
return false; | |
$page.val(page); | |
$form.trigger("submit"); | |
return false; | |
}); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment