用户操作
[即时聊天] [发私信] [加为好友]
debugboyID:dboyII
689次访问,排名2万外,好友0人,关注者1人。
Responsility, Loyality, Fortitude
dboyII的文章
原创 1 篇
翻译 1 篇
转载 0 篇
评论 1 篇
最近评论
lsq8377:asdfasdfasdf
文章分类
收藏
    相册
    .NET Article
    .NET Blog
    Terry 博客
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    翻译 [A1.ASP-NET]Gridview控件高效异步更新与实验(翻译)收藏

     | 旧一篇: [A1.ASP-NET]DayPilot Calendar控件异步更新的Drag和Drop实验

    1. 前言

    前些天在http://www.ajaxmatters.com上找到一篇关于不使用UpdatePanel来实现Gridview相关ajax操作的文章,回家按部就班地做了一个实验,感觉不错,里面涉及到的编程技术比我在国内网站上查到的要更全面一些,特此翻译全文,以飨读者。

    2. 全文翻译

    【译者注: 文章来自www.ajaxmatters.com论坛】

    【上篇】

    本文详细描述了如何使用.net的ICallbackEventHandler接口开发包括排序(sorting), 分页显示(paging), 改变页长(page length change)AJAX Gridview控件, 我在下面会介绍到具体编程,读者也可以在文章最后下载到所有的源码。

    本例开发的Gridview控件的基本功能如下(所有操作都是异步的):

    • 点击列名旁边的箭头升序或者降序排列数据
    • 翻页
    • 改变每页显示的数目
    在本例中,我们将会用到一个ASP.NET中最为强大的特性 - RenderControl。该方法能使我们方便地(在服务器端 - 译者注)通过HtmlTextWriter和StirngWriter对象访问到一个控件的HTML代码。
    示例:
    using (StringWriter sw = new StringWriter())
    {

                HtmlTextWriter htw 
    = new HtmlTextWriter(sw);

                _grid.RenderControl(htw);

                htw.Flush();

                
    string result = sw.ToString();

    }
    我们获取到grid控件的html格式的代码并赋给一个string变量 - 这个工作是在绑定控件数据源之后做的。

    现在,我们从开发UI代码开始一步一步完成这个示例程序:
    首先,在网页的<form>标签内写下如下代码,创建一个Gridview和Dropdownlist控件:
    <div id="Gridview" >
             
    <asp:GridView EnableViewState="false" runat="server" id="_grid" OnRowDataBound="_grid_RowDataBound"          AllowPaging="True" >
             
    </asp:GridView>

    <br />

    </div> Change page length to -- 

    <asp:DropDownList ID="ddl" runat="server">

    </asp:DropDownList>
    注意Gridview控件的RowDataBound事件已经激活了。

    下一步,我们来创建一个DataTable, 作为Gridview控件的数据源:
    public DataTable _sampleData
    {

            
    get {

                DataTable dt 
    = (DataTable)ViewState["DataTable"];

                
    if(dt == null)

                
    {

                    dt 
    = new DataTable();

                dt.Columns.Add(
    new DataColumn("Contact Name",typeof(string)));

                dt.Columns.Add(
    new DataColumn("Company Name"typeof(string)));

                dt.Columns.Add(
    new DataColumn("City"typeof(string)));

                dt.Columns.Add(
    new DataColumn("Country"typeof(string))); 


                dt.Rows.Add(
    new object[] "Maria Anders" ,"Alfreds Futterkiste","Berlin","Germany"});

                dt.Rows.Add(
    new object[] "Ana Trujillo" ,"Emparedados y helados ","México D.F.","Mexico"});

                dt.Rows.Add(
    new object[] "Antonio Moreno""Antonio Moreno Taquería""México D.F.","Mexico" });

    ViewState[
    "DataTable"= dt;

                }


                
    return dt;

    }
    我们使用ViewState 而不是Session 变量来存放DataTable.
    比如, ViewState["DataTable"] = dt;
    用session可以缓存整个网站的变量, ViewState就只存某个页面的。在绑定数据的时候,我们只需要写_grid.DataSource = _sampleData即可。

    下面是Gridview的4个操作方法:
    • 排序
    private void sortGrid(string Argument , string pageLength) 


         DataView dv 
    = _sampleData.DefaultView;

         result 
    = "";

           dv.Sort 
    = Argument;

           _grid.DataSource 
    = dv;

           _grid.PageSize 
    = Convert.ToInt16(pageLength);

           _grid.DataBind();

           renderGrid(_grid);

    }


    • 翻页
    private void changePage(string Argument , string       pageLength) 
    {
             result 
    = "";

            _grid.DataSource 
    = _sampleData;

            _grid.PageSize 
    = Convert.ToInt16(pageLength);

            _grid.PageIndex 
    = Convert.ToInt16(Argument);

            _grid.DataBind();

            renderGrid(_grid);

    }

    • 改变每页显示长度
    private void changePageLength(string Argument,  string pageLength) 
     
    {

          result 
    = "";

         _grid.DataSource 
    = _sampleData;

         _grid.PageSize 
    = Convert.ToInt16(Argument);

         _grid.DataBind();

         renderGrid(_grid);

    //pageLength is not used

     }
     
    • 刷新Gridview
    private void renderGrid(GridView _grid) 

         
    using (StringWriter sw = new StringWriter())
         
    {

                HtmlTextWriter htw 
    = new HtmlTextWriter(sw);

                _grid.RenderControl(htw);

                htw.Flush();

                result 
    = sw.ToString();

            }

    }
    上述4个方法的名称显示了其实现的功能,而前三个的第二个参数'pageLength'是dropdownlist控件选定的值。

    我们需要另外4个方法来实现ICallbackEventHandler异步回调 - 两个是javascript方法(其一对服务器端回调,其二用来接收服务器端返回的值并做异步刷新), 两个是服务器端的方法( RaiseCallbackEvent 和GetCallbackResult , 译者注:ICallbackEventHandler的两个接口方法,前面的用来响应客户端回调,后面的用来返回操作结果)。

    JavaScript方法如下:
    function UpdateGrid(args) 
    {

    args 
    = args + "$" + window.document.getElementById('ddl').value;

    <%= ClientScript.GetCallbackEventReference(this,"args""ShowResult"null%>

    }
    在页面装载完成之后,我们将在页面的源代码里面看到上面的代码编程了这个样子:
    function UpdateGrid(args)
    {

           args 
    = args + "$" +            window.document.getElementById('ddl').value;

            WebForm_DoCallback(
    '__Page',args,ShowResult,null,null,false);

    }
     


    在回调的时候,我们会触发服务器端的一个事件,因此,UpdateGrid(args)方法需要放在<form>标签之内,否则的话会发生一个JavaScript错误。我们通过Page.ClientScript.RegisterClientScriptBlock方法来注册这个JavaScipt方法,这样的话它将仅出现在<form>标签之内。

    function ShowResult(eventArgument,context)     
    {
        window.document.getElementById(
    'Gridview').innerHTML = eventArgument;
    }
    这个方法将在服务器端响应客户端之后触发,它负责处理服务器端的返回值。在这里我们只是简单的用返回值替换掉innerHTML属性。innerHTML包含了需要更新的Gridview的HTML代码。

    服务器端的代码如下:
    public string GetCallbackResult() 
    {
        
    return result;
    }
    该方法返回在ShowResult客户端方法中设置innerHTML的结果。

    public void RaiseCallbackEvent(string eventArgument) 
    {
        
    string[] args = eventArgument.Split('$');

        
    if (args[0== "sort"{ sortGrid(args[1], args[2]); }

        
    else if (args[0== "changePage"{ changePage(args[1], args[2]); }

        
    else if (args[0== "changePageLength"{ changePageLength(args[1], args[2]); }
    }
    该函数输入参数形如"changePage$1$10" 或者"sort$1$10" 或者 "changePageLength$1$10" 或者 "sort$Contact Name Asc" 或者 “sort$Contact Name Desc$10”, 我们用字符串解析函数得到下列参数列表:
    • 操作名称(Action);
    • Gridview控件的页码(Page Index of the Gridview);
    • Dropdownlist的每页显示长度(Page size from the dropdownlist)
    在RaiseCallbackEvent方法中我们调用了一些处理具体操作的函数,每个函数都会设置Gridview更新之后的HTML代码给返回参数。

    页面装载代码:
    if (!IsPostBack)
    {
                _grid.DataSource 
    = _sampleData;

                _grid.DataBind();

                ddl.Items.Add(
    "10");

                ddl.Items.Add(
    "20");

                ddl.Items.Add(
    "30");

                ddl.Attributes.Add(
    "onchange""javascript:UpdateGrid('changePageLength$' + this.value);");
    }
    这里设置Gridview控件每页的显示长度。

    现在实现Gridview的RowDataBound事件,为了列排序功能,修改了Gridview控件的列头:
    if (e.Row.RowType == DataControlRowType.Header)
    {

        
    for (int i = 0; i < e.Row.Cells.Count; i++)
         
    {

                  e.Row.Cells[i].Text 
    = string.Format("{0}<img alt="Ascending" src="Images/up.jpg" onclick="UpdateGrid('sort${0} Asc')"; /><img alt="Descending" src="Images/down.jpg" onclick="UpdateGrid('sort${0} desc') "; />", e.Row.Cells[i].Text);

         }

    }

    列头上加上了上下箭头,点击他们的时候将调用UpdateGrid方法(在客户端 - 译者注)回调服务器端的升序和降序排列方法。

    随后我们对页码行(Page Row)做一些绑定时的修改,使页码能够在点击的时候调用UpdateGrid方法。
    else if (e.Row.RowType == DataControlRowType.Pager)
    {

           GridView gdv 
    = (GridView)sender;

           
    int _pageCount = gdv.PageCount;

           e.Row.Cells[
    0].Text = "";

           
    for (int i = 0; i < _pageCount; i++)
            
    {
                 HyperLink hyp 
    = new HyperLink();

                 hyp.Text 
    = i.ToString() + "&nbsp;";

                 hyp.Attributes.Add(
    "href""javascript:UpdateGrid('changePage$" + i + "');");

                 e.Row.Cells[
    0].Controls.Add(hyp);

                 Label l 
    = new Label();

                 l.Text 
    = "&nbsp;";

                e.Row.Cells[
    0].Controls.Add(l);

                 hyp 
    = null;
            }

    }
     

    _pageCount 用来保存Gridview控件的页数,为了显示页码,我们使用了HyperLink + Label +空格 的方式。

    最后,把EnableViewState属性设置为false,用来减轻页面的负担。


    【下篇】
    上篇我们使用了ICallbackEventHandler接口实现了一个AJAX的Gridview控件,功能如下:
    • 点击列名旁边的上下小箭头实现升序和降序排列的功能
    • 翻页
    • 改变每页显示长度
    本篇将讨论如何通过双击数据格(grid cell)来修改格子里的数据,实现服务器端数据更新的时候来异步刷新页面的功能。关键点如下:
    • 在Page Load的时候只绑定一次数据到Gridview控件
    • 只有当更新数据要求传到服务器端的时候才更新Gridview控件
    UI代码:
     <div id="Gridview">
        
    <asp:GridView EnableViewState="false" runat="server" id="_grid" OnRowDataBound="_grid_RowDataBound">
        
    </asp:GridView>
       
    <span id ="ServerMsg"></span>
    </div>
    <br />
    <input type=button value="Update" onclick="javascript: JSUpdateTable ();" />
    <script language="javascript">
        
    function UpdateGrid(args)
        
    {
            
    <%= ClientScript.GetCallbackEventReference(this,"args""ShowResult"null%>;
        }

    </script>

    使用一个DataTable作为数据源:
    public DataTable _sampleData
    {
            
    get 
            
    {
                DataTable dt 
    = (DataTable) Session["DataTable"];
                
    if(dt == null)
                
    {
                    dt 
    = new DataTable();
                    dt.Columns.Add(
    new DataColumn("Contact                                Name",typeof(string)));
                    dt.Columns.Add(
    new DataColumn("Company Name"typeof(string)));
                    dt.Columns.Add(
    new DataColumn("City"typeof(string)));
                    dt.Columns.Add(
    new DataColumn("Country"typeof(string)));

                    dt.Rows.Add(
    new object[] "Maria Anders" ,"Alfreds Futterkiste","Berlin","Germany"});
                    dt.Rows.Add(
    new object[] "Ana Trujillo" ,"Emparedados y helados ","México D.F.","Mexico"});
                    dt.Rows.Add(
    new object[] "Antonio Moreno""Antonio Moreno Taquería""México D.F.","Mexico" });
                    Session[
    "DataTable"= dt;
                }

                
    return dt;
            }

            
    set
            
    {
                Session[
    "DataTable"= value;
            }

    }
    注意:在这里我们使用Session而不是ViewState存放DataTable变量,因为我们需要在服务器端更新数据,如果使用ViewState的话需要对页面进行回发(post back)才行。

    使用下面的代码把Datatable绑定到Gridview控件: _grid.DataSource = _sampleData; 更新的时候: _sampleData = _tempTable, _tempTable是更新了数据之后的临时DataTable变量。

    页面类继承ICallbackEventHandler接口:
    public partial class Default: System.Web.UI.Page, ICallbackEventHandler

    添加RaiseCallbackEvent方法和GetCallbackResult方法:
    public void RaiseCallbackEvent(string eventArgument)
    {
            
    string[] args = eventArgument.Split('$');
            
    if (args[0== "updateTable") updateTable(args[1]);
    }