RadControls for ASP.NET AJAX是一套挺優秀的ASP.NET元件庫,包辦了開發ASP.NET專案時需要用到的大小控制項(如: Grid、日期選擇器、數字輸入欄位、頁籤... 等等),手上有幾個專案裡就是利用RadGrid的Client-Side Data-Binding實現AJAX式的換頁及重排效果,但中年人記憶消失之快已到了令人心驚的地步,每次要寫類似應用都要花上大半天回頭從舊程式找範例(要命的是連在哪個專案寫過都要想半天),於是催生了這篇"銀杏文"。

RadGridAjaxSample.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="RadGridAjaxSample.aspx.cs"
    Inherits="RadGridAjaxSample" %>
 
<%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
<!DOCTYPE html>
<html>
<head runat="server">
    <title>RadGrid AJAX Sample</title>
    <style>
        body,input { font-size: 9pt; }
        span.hi-lite { color: red; }
    </style>
    <script type="text/javascript"
            src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.js"> </script>
    <script>
        function dataBinding(sender, args) {
            //取得要傳給WebMethod的參數
            var params = args.get_methodArguments();
            //透過$.extend()加上自訂參數
            $.extend(params, { "keywd": $("#tKeyword").val() });
        }
        function dataBound(sender, args) {
            //AJAX資料Bind完成後觸發
            var kw = $("#tKeyword").val();
            //若有設關鍵字,做Highlight處理
            if (kw.length > 0) {
                var re = new RegExp(kw, "g");
                $(".u-name").each(function () {
                    var $td = $(this);
                    $td.html($td.text()
                       .replace(re, "<span class='hi-lite'>$&</span>"));
                });
            }
        }
        $(function () {
            //示範由前端觸發資料重新查詢
            $("#bQuery").click(function () {
                $find("RadGrid1").get_masterTableView().rebind();
            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <div style="padding: 10px;">
    關鍵字: <input id="tKeyword" /><input type="button" value="查詢" id="bQuery" />
    </div>
    <telerik:RadGrid ID="RadGrid1" runat="server" Width="400px" 
     AutoGenerateColumns="False" CellSpacing="0" GridLines="None" AllowPaging="True" 
     AllowSorting="true" PageSize="10">
        <MasterTableView>
            <Columns>
                <telerik:GridBoundColumn HeaderText="會員編號"
                    DataField="UserNo" UniqueName="UserNo">
                    <HeaderStyle Width="100px" />
                </telerik:GridBoundColumn>
                <telerik:GridBoundColumn HeaderText="會員名稱"
                    DataField="UserName" UniqueName="UserName">
                    <HeaderStyle Width="100px" />
                    <ItemStyle CssClass="u-name" />
                </telerik:GridBoundColumn>
                <telerik:GridBoundColumn HeaderText="加入日期" DataField="RegDate" 
                 UniqueName="RegDate" DataFormatString="{0:yyyy/MM/dd}">
                    <HeaderStyle Width="100px" />
                </telerik:GridBoundColumn>
                <telerik:GridBoundColumn HeaderText="累積點數"
                    DataField="Points" UniqueName="Points" DataFormatString="{0:N0}">
                    <HeaderStyle Width="100px" />
                    <ItemStyle HorizontalAlign="Right" />
                </telerik:GridBoundColumn>
            </Columns>
        </MasterTableView>
        <AlternatingItemStyle HorizontalAlign="Center" />
        <HeaderStyle HorizontalAlign="Center" />
        <ItemStyle HorizontalAlign="Center" />
        <FilterMenu EnableImageSprites="False">
        </FilterMenu>
        <HeaderContextMenu CssClass="GridContextMenu GridContextMenu_Default">
        </HeaderContextMenu>
        <ClientSettings>
            <DataBinding Location="RadGridAjaxSample.aspx" SelectMethod="GetData">
            </DataBinding>
            <ClientEvents OnDataBinding="dataBinding" OnDataBound="dataBound" />
        </ClientSettings>
    </telerik:RadGrid>
    </form>
</body>
</html>

[說明]

  1. 透過DataBinding指定呼叫RadGridAjaxSample.aspx的GetData WebMethod讀取資料(也可寫成一般ASHX,但要自己由POST內容解析取出分頁、篩選參數,要花點功)
  2. function dataBinding會在AJAX取資料前觸發,在此示範如何帶入額外參數(關鍵字查詢)
  3. function dataBound會在AJAX取回資料並Bind到HTML表格後觸發,在此示範用jQuery將會員名稱欄位出現的關鍵字標為紅字
  4. 要由Client端觸重新查詢的寫法為: $find("RadGrid1").get_masterTableView().rebind();
    ($find是ASP.NET AJAX的Client端函數,Telerik的這套元件仍以ASP.NET AJAX為基礎,到了MVC版本才是以jQuery為底)

 

後端程式RadGridAjaxSample.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Telerik.Web.UI;
using System.Web.Services;
using System.Drawing;
using System.Reflection;
 
public partial class RadGridAjaxSample : System.Web.UI.Page
{
    //模擬資料物件
    public class SimMemberInfo 
    {
        public string UserNo; //會員編號
        public string UserName; //會員名稱
        public DateTime RegDate; //註冊日期
        public int Points; //累積點數
    }
    //查詢結果,包含資料物件集合(已分頁)以及總筆數
    public class RadGridQueryResult<T>
    {
        public int TotalCount;
        public List<T> Items;
    }
    static List<SimMemberInfo> _SimuDataStore = null;
    //模擬對資料庫進行關鍵字查詢,並依要求分頁及排序
    public static RadGridQueryResult<SimMemberInfo> 
        QuerySimuData(string keywd, int stPos, int count, string sortBy)
    {
        if (_SimuDataStore == null)
        {
            Random rnd = new Random();
            //借用具名顏色名稱來產生隨機資料
            string[] colorNames =typeof(Color)
                .GetProperties(BindingFlags.Static | BindingFlags.Public)
                .Select(o => o.Name).ToArray();
            _SimuDataStore = 
                colorNames
                .Select(cn => new SimMemberInfo()
                {
                    UserNo = string.Format("C{0:00000}", rnd.Next(99999)),
                    UserName = cn,
                    RegDate = DateTime.Today.AddDays(- rnd.Next(1000)),
                    Points = rnd.Next(9999)
                }).ToList();
        }
        //指定關鍵字時,使用Contains()對UserName進行比對
        var q = _SimuDataStore.Where(o => 
            string.IsNullOrEmpty(keywd) || o.UserName.Contains(keywd));
        if (!string.IsNullOrEmpty(sortBy))
        {
            //宣告一個函數可傳回SimMemberInfo之指定屬性值用於依動態欄位排序
            Func<SimMemberInfo, string, string> GetColString =
                (o, c) =>
                {
                    switch(c)
                    {
                        case "UserNo": return o.UserNo;
                        case "UserName": return o.UserName;
                        case "RegDate": return o.RegDate.ToString("yyyyMMdd");
                        case "Points": return o.Points.ToString();
                        default: throw new ArgumentException();
                    }
                };
            //sortBy格式為ColName ASC或ColName DESC
            string[] p = sortBy.Split(' ');
            if (p[1] == "ASC")
                q = q.OrderBy(o => GetColString(o, p[0]));
            else
                q = q.OrderByDescending(o => GetColString(o, p[0]));
        }
        return new RadGridQueryResult<SimMemberInfo>()
        {
            TotalCount = q.Count(),
            Items = q.Skip(stPos).Take(count).ToList()
        };
    }
 
    [WebMethod()]
    public static Dictionary<string, object> GetData(
        //前四個參數是RadGrid制式要求,分別為: 起始筆數、每頁筆數、排序設定、篩選設定
        int startRowIndex, int maximumRows, List<GridSortExpression> sortExpression, 
        List<GridFilterExpression> filterExpression,
        //若前端用args.get_methodArguments()加入額外參數,在此要宣告參數接收
        string keywd)
    {
        Dictionary<string, object> data = new Dictionary<string, object>();
        //取得排序參數(只實做支援單欄排序)
        GridSortExpression gse = sortExpression.FirstOrDefault();
        string sortBy = gse != null ? 
            string.Format("{0} {1}", gse.FieldName, gse.SortOrderAsString()) : "";
        //模擬呼叫資料庫進行查詢(傳入關鍵字、分頁參數及排序欄位)
        var res = QuerySimuData(keywd, startRowIndex, maximumRows, sortBy);
        data.Add("Data", res.Items);
        data.Add("Count", res.TotalCount);
        return data;
    }
 
    protected void Page_Load(object sender, EventArgs e)
    {
    }
}

[說明]

  1. 為了簡化起見,沒動用資料庫,只自訂了SimMemberInfo類別模擬資料物件,並以隨機方式產生模擬資料(我用Color.Red等具名顏色來當作會員名稱,很有創意吧!)
  2. WebMethod GetData要接入int startRowIndex, int maximumRows, List<GridSortExpression> sortExpression, List<GridFilterExpression> filterExpression等參數,傳回經篩選(本範例中未實做)、分好頁、排序過的資料集合,同時要回報總筆數。
  3. GetData的keywd參數是前端function dataBinding()時額外加傳的
  4. QuerySimuData中動了點手腳(透過GetColString函數)實現動態指定排序欄位,這在不同資料來源時玩法不同 (2014-04-28 範例中一律將欄位轉為字串排序,故會出現134比1234大的不合理結果,有Bug待修)

以下為執行畫面:

由於配合Telerik元件才能執行,大家不一定能立即在自己的機器上試用,所以我準備了一個線上展示,有興趣的人可以看看。


Comments

# by 謝謝分享

謝謝分享,每看一篇文章就覺得自己成長了一些@@ 這套元件還真貴,雖然蠻強大的 囧

# by Miller

感謝分享,每次看您的教學,都受益良多。 抱歉,最近也剛好注意到這套元件,請問您是直接在網路下單,還是台灣有經銷商可以購買? 謝謝~

# by Jeffrey

to Miller, 我們是直接網路刷卡下單取得授權序號,客服支援則透過官方網站或電子郵件管道取得(英文),回應速度挺快的。 現在有很多軟體(尤其是元件類)只走網路銷售,會計部門應該已認命接受才對(呵);若採購部門堅持要發票方能報帳,國內似乎也有代理廠商能代購Telerik,用Telerik+經銷查查不難找到。

# by Miller

To Jeffrey, 非常感謝您的經驗分享與建議,很幸運,公司的採購願意協助購買,下載試用版試用中 ︿ ︿

# by Haw

線上展示的累積點數排序怪怪的, 剛好看到,通知您一聲

# by Jeffrey

to Haw, 謝謝回饋,程式將數字轉成字串後比對,因而形成134比1234大的不合理情況,應轉成數字再比較才合理。先加註在文中,日後再找時間修正。

# by mark

黑大 您好 我常常拜讀您的文章 您的文章非常受用 感謝您的無私分享 線上展示 沒有分頁的時候 細項有部份查詢關鍵字不會反紅

# by Jeffrey

to mark, 沒分頁是指筆數不足一頁的狀況嗎?測試Gray有反紅( http://i.imgur.com/WYnGpOb.gif?1 ),可否提供你的測試案例我查查?

Post a comment