在 Web Form 做 Grid 換頁時,通常會先將資料把所有資料先建入 DataTable,再使用控制項接收這些資料,換頁時,就將這些資料經過處理再顯示。然後再做資料搜尋,會再去要一次資料,如此一來,在每次產生 GridView 時,都會使用同一份資料篩選,等於是網頁上有一份資料在做處理,如果資料量一大,吃的資源也大,處理與顯示時相對的就慢。
使用 Extjs 做 Grid.Panel 分頁,一般來說會先將所有資料載到頁面,再做分頁,只是 Extjs 接收資料格式必須要在最根層加上總數量,這樣才能知道該頁顯示幾頁,總共有幾頁,所以格式必須符合如下:
{
"totalCount": "6679",
"topics": [
{
// ....
},
{
// ....
},
{
// ....
},
{
// ....
},
{
// ....
}
// ...
]
}
而符合這種格式必須在 Web Api 段做些許調整,要多寫一個屬性讓 API 能使用,可以參考:
Web API, OData, $inlinecount and testing,程式碼如下
public class InlineCountQueryableAttribute : QueryableAttribute
{
private static MethodInfo _createPageResult =
typeof(InlineCountQueryableAttribute)
.GetMethods(BindingFlags.Static | BindingFlags.NonPublic)
.Single(m => m.Name == "CreatePageResult");
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
base.OnActionExecuted(actionExecutedContext);
HttpRequestMessage request = actionExecutedContext.Request;
HttpResponseMessage response = actionExecutedContext.Response;
IQueryable result;
if (response.IsSuccessStatusCode
&& response.TryGetContentValue<IQueryable>(out result))
{
long? inlineCount = request.GetInlineCount();
if (inlineCount != null)
{
actionExecutedContext.Response = _createPageResult.MakeGenericMethod(result.ElementType).Invoke(
null, new object[] { request, request.GetInlineCount(), request.GetNextPageLink(), result }) as HttpResponseMessage;
}
}
}
internal static HttpResponseMessage CreatePageResult<T>(HttpRequestMessage request, long? count, Uri nextpageLink, IEnumerable<T> results)
{
return request.CreateResponse(HttpStatusCode.OK, new PageResult<T>(results, nextpageLink, count));
}
}
在 API 加上此屬性:
[InlineCountQueryable]
public IEnumerable GetEmployees()
{
IEnumerable employees = db.Employees.ToList();
foreach (Employees employee in employees)
{
employee.Employees1 = null;
employee.Employees2 = null;
}
return employees;
}
執行結果如下:
{
Count: 15,
Items: [
{ ... },
{ ... },
...
],
NextPageLink: XXX,
}
這樣輸出結果與 Extjs Grid.Panel 做分頁要接收的格式已經 95% 相似了,而換頁時通常自動會帶 page 、 start 和 limit,page 感覺只是顯示用,而 start 和 limit 的部分可以使用 API 的 Queryable 來解決,它等同於 Queryable 的 $skip 和 $top:
首先我們先看如何在 grid.Panel 加上分頁,加上一個屬性即可,其中 store 為資料來源:
bbar: Ext.create('Ext.PagingToolbar', {
store: store,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: "No topics to display",
}),
因為每一次換頁就會與 store 要一次資料,所以必須針對來源做修改:
var store = Ext.create('Ext.data.JsonStore', {
storeId: 'store',
model: 'Model',
pageSize: 3,
proxy: {
type: 'ajax',
url: 'http://localhost:8090/api/Control?$inlinecount=allpages',
reader: {
type: 'json',
root: 'Items',
totalProperty: 'Count',
},
startParam: '$skip',
limitParam: '$top'
},
autoLoad: true,
listeners: {
load: function (store, records, options) {
}
},
});
其中 PageSize 為每頁顯示數量,而 startParam、limitParam 則是改變它換頁帶的參數,最後執行就可以看到每換一次頁就會重新與 API 要一次資料,這樣一來頁面負擔不會太重,同時又做到速度與流量兼顧的結果。