Continuing with the WebGrid, I first made it strongly typed. To achieve that, I created a derived type WebGrid
Next I added server paging. Why wouldn't I use the built-in paging? Well, the database table behind WebGrid may have hundreds of records. I wouldn't want to pass it all to my ViewModel and then to the view just to display 5 or 10 of the records I actually need. It is handy that the WebGrid paging is in the form of http://website/Items/ShowAll?page=3. This way my controller knows which page is to be displayed and can preselect the data just for this page only.
To implement paging, I added the TotalRows to the model - that will specify the total number of records in the database table.
The controller method now looks as follows:
public ActionResult Index(int page=1) { int totalRecords; List<YahooData> datas = GetData(out totalRecords, pageSize: 5, pageIndex: page - 1); List<YahooSymbol> symbols = db.YahooSymbols.ToList(); YahooSymbol symbol = symbols.First(); int id = symbol.YahooSymbolID; return View(new YahooViewModel(id, symbol, symbols, datas, totalRecords)); } public List<YahooData> GetData(out int totalRecords, int pageSize, int pageIndex) { List<YahooData> data = GetData(); totalRecords = data.Count; if(pageSize > 0 && pageIndex >=0) { data = data.Skip(pageIndex*pageSize).Take(pageSize).ToList(); } return data.ToList(); }
The concept is quite simple - get data from the database table, identify the records that will be displayed on the WebGrid page that is requested, and only pass those records to the view. The WebGrid part of the view now looks as follows
<div id="webgrid" style="float:left; min-width:500px;"> @{ var grid = new WebGrid<ViewModels.YahooData>(null, rowsPerPage: 5, defaultSort: "YahooSymbolName"); grid.Bind(Model.Datas, rowCount: Model.TotalRows, autoSortAndPage: false); @grid.GetHtml(columns: grid.Columns( grid.Column("DataName", header:"Company", format:@<text>@Html.ActionLink((string)item.DataName, "Details", "Company", new {id=item.SymbolId}, null)</text>), grid.Column("DateTime", header:"Time", style:"time", format:@<text>@item.DateTime.ToString("dd/MM/yyyy hh:mm")</text>), grid.Column("LTP"), grid.Column("Volume"), grid.Column("Ask"), grid.Column("Bid"), grid.Column("High"), grid.Column("Low")), tableStyle: "webGrid", headerStyle: "header", alternatingRowStyle: "alt"); } </div>
My plan from here is to implement AJAX updates to the WebGrid content.
The strongly typed WebGrid samples:
//Strongly Typed WebGrid public class WebGrid<T> : WebGrid { // Wrapper for System.Web.Helpers.WebGrid that preserves the item type from the data source public WebGrid(IEnumerable<T> source = null, IEnumerable<string> columnNames = null, string defaultSort = null, int rowsPerPage = 10, bool canPage = true, bool canSort = true, string ajaxUpdateContainerId = null, string ajaxUpdateCallback = null, string fieldNamePrefix = null, string pageFieldName = null, string selectionFieldName = null, string sortFieldName = null, string sortDirectionFieldName = null) : base(source.SafeCast<object>(), columnNames, defaultSort, rowsPerPage, canPage, canSort, ajaxUpdateContainerId, ajaxUpdateCallback, fieldNamePrefix, pageFieldName, selectionFieldName, sortFieldName, sortDirectionFieldName) { } public WebGridColumn Column(string columnName = null, string header = null, Func<T, object> format = null, string style = null, bool canSort = true) { Func<dynamic, object> wrappedFormat = null; if (format != null) { wrappedFormat = o => format((T)o.Value); } WebGridColumn column = base.Column(columnName, header, wrappedFormat, style, canSort); return column; } public WebGrid<T> Bind(IEnumerable<T> source, IEnumerable<string> columnNames = null, bool autoSortAndPage = true, int rowCount = -1) { base.Bind(source.SafeCast<object>(), columnNames, autoSortAndPage, rowCount); return this; } } public static class EnumerableExtensions { public static IEnumerable<TTarget> SafeCast<TTarget>(this IEnumerable source) { return source == null ? null : source.Cast<TTarget>(); } }
//WebGrid extensions public static class WebGridExtensions { // Light-weight wrapper around the constructor for WebGrid so that we get take advantage of compiler type inference public static WebGrid<T> Grid<T>(this HtmlHelper htmlHelper, IEnumerable<T> source, IEnumerable<string> columnNames = null, string defaultSort = null, int rowsPerPage = 10, bool canPage = true, bool canSort = true, string ajaxUpdateContainerId = null, string ajaxUpdateCallback = null, string fieldNamePrefix = null, string pageFieldName = null, string selectionFieldName = null, string sortFieldName = null, string sortDirectionFieldName = null) { return new WebGrid<T>(source, columnNames, defaultSort, rowsPerPage, canPage, canSort, ajaxUpdateContainerId, ajaxUpdateCallback, fieldNamePrefix, pageFieldName, selectionFieldName, sortFieldName, sortDirectionFieldName); } // Light-weight wrapper around the constructor for WebGrid so that we get take advantage of compiler type inference and to automatically call Bind to disable the automatic paging and sorting (use this for server-side paging) public static WebGrid<T> ServerPagedGrid<T>(this HtmlHelper htmlHelper, IEnumerable<T> source, int totalRows, IEnumerable<string> columnNames = null, string defaultSort = null, int rowsPerPage = 10, bool canPage = true, bool canSort = true, string ajaxUpdateContainerId = null, string ajaxUpdateCallback = null, string fieldNamePrefix = null, string pageFieldName = null, string selectionFieldName = null, string sortFieldName = null, string sortDirectionFieldName = null) { var webGrid = new WebGrid<T>(null, columnNames, defaultSort, rowsPerPage, canPage, canSort, ajaxUpdateContainerId, ajaxUpdateCallback, fieldNamePrefix, pageFieldName, selectionFieldName, sortFieldName, sortDirectionFieldName); return webGrid.Bind(source, rowCount: totalRows, autoSortAndPage: false); ; } }
References
Get the Most out of WebGrid in ASP.NET MVCby Evgeny. Also posted on my website
No comments:
Post a Comment