zoukankan      html  css  js  c++  java
  • Ext.Net 1.2.0_Ext.Net.GridPanel 实现多级Grid

    实现多级 Grid 在 Ext.Net Demo 里有,本文旨在进一步说明它的实现,以及在此基础上,说明如何在多级Grid上,进行增删改等操作。

    本文内容

    • 多级 Grid 概述
    • 实现多级 Grid

    多级 Grid 概述

    有这样一个实现:Grid 数据的某行下,也包含数据,单击或双击时,需要展开。默认情况,Grid 只显示第一级,当点击某行记录最前边的“+”,或双击某行记录时,展开与该记录相关的数据。对于数据库来说,最一般的是——自连表。

    在暂不考虑数据分页的前提下,问问自己:

    • 首先,假设我们处于 Ajax 时代之前,没有任何三方组件可以提供这个功能,你对 JavaScript 只有一定的了解,但是对 C# 或是 Java 很熟练,那么若想实现这个功能你能想到什么?
    • 其次,假设我们处于 Ajax 时代之前,没有任何三方组件可以提供这个功能,但你已经对 JSON 和 JavaScript 都很熟悉,那么若想实现这个功能你能想到什么?
    • 最后,假设我们已经处于 Ajax 时代,没有现成的三方组件可以很好地提供这个功能,但是你对 JSON 和 jQuery 很熟悉,那么若想实现这个功能你能想到什么?

    对于第一个假设,因为没有异步、没有局部刷新,我们只能将数据全部从数据库读出来,因为你对JavaScript 还不甚了解,所以只能利用 C# 或 JavaScrit 在服务器端创建嵌套的 <div> 或是 <table>(这需要一个相对复杂的逻辑),还要为 Grid 的展开创建客户端代码,绝大多数操作都在服务器端——这个实现绝不简单。要命的是,效率实在太低,暂且不说它完全需要回发,用户体验也差到极致。

    对于第二个假设,没有异步、没有局部刷新,更没有现成三方组件可用,但是你已对 JSON 和 JavaScrit 有很好的了解,此时,你能想到的,也许是,从服务器端把数据全部读出来,因为数据库表本身就是自连表(比如,有 ID,有 PARENTID),无需进行复杂的业务处理,只需要将数据转换成 JSON 格式,剩下的工作,完全在客户端完成(利用 JavaScript 解析 JSON)——这个也不大容易。但至少比第一个强,客户端完成绝大多数操作。

    对于第三个假设,有异步、有局部刷新,更关键的是你对 JSON 和 jQuery 都很熟悉,那完全可以从数据库先获得第一级的数据,当用户单击或双击时,利用 jQuery,发出 Ajax 请求,从数据库获得指定记录下的相关数据,然后在回调成功时,添加到指定记录下……——这个思路不仅清晰,而且实现相对简单,用户体验也好,都是局部刷新,效率也高。

    其实,说了这么多,仅仅是锻炼你的思维。因为现在很多三方组件都提供这个功能。如果你能体会人家的设计思想,以及实现一个功能时的思路,使用三方组件其实很容易,虽然看上去很复杂。

    实现多级 Grid

    首先看看,客户端代码都有什么,如下所示:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ExtNetMultiGridPanel._Default" %>
     
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
        <ext:ResourcePlaceHolder ID="ResourcePlaceHolder1" runat="server" Mode="Script" />
     
        <script type="text/javascript">
       1:  
       2:         window.lookup = {};
       3:  
       4:         var params = {
       5:             action: " ",
       6:             ui: gridUIParams,
       7:             setAction: function(action) {
       8:                 this.action = action;
       9:             },
      10:             setParams: function(recId, level) {
      11:                 if (arguments.length == 2) {
      12:                     if (this.ui == undefined) {
      13:                         this.ui = gridUIParams;
      14:                     }
      15:                     this.ui.id = recId;
      16:                     this.ui.level = level;
      17:                 }
      18:                 else if (arguments.length == 0) {
      19:                     if (this.ui == undefined) {
      20:                         this.ui = gridUIParams;
      21:                     }
      22:                     this.ui.id = " ";
      23:                     this.ui.level = " ";
      24:                 }
      25:             },
      26:             toJson: function() {
      27:                 return Ext.encode(this);
      28:             }
      29:         };
      30:  
      31:         var gridUIParams = {
      32:             id: "",
      33:             level: ""
      34:         };
      35:  
      36:         var selectedRow = function(recId, level, obj) {
      37:             params.setParams(recId, level);
      38:             obj.setValue(params.toJson());
      39:         };
      40:  
      41:         var setAction = function(action, obj) {
      42:             var paras = Ext.decode(obj.getValue());
      43:             params.action = action;
      44:             if (paras.ui.id != undefined) params.ui.id = paras.ui.id;
      45:             if (paras.ui.level != undefined) params.ui.level = paras.ui.level;
      46:             obj.setValue(params.toJson());
      47:         };
      48:  
      49:         var clean = function(view, isDestroy) {
      50:             var controls = window.lookup[view.grid.id] || {},
      51:                 ids = [];
      52:  
      53:             for (var c in controls) {
      54:                 ids.push(controls[c].id || controls[c].storeId);
      55:             }
      56:  
      57:             if (ids.length > 0) {
      58:                 if (isDestroy !== true) {
      59:                     view.grid.getRowExpander().collapseAll();
      60:                 }
      61:  
      62:                 for (var i = 0; i < ids.length; i++) {
      63:                     removeFromCache(ids[i], view.grid.id);
      64:                 }
      65:             }
      66:         };
      67:  
      68:         var addToCache = function(c, parent) {
      69:             window.lookup[parent] = window.lookup[parent] || {};
      70:             window.lookup[parent][c] = window[c];
      71:         };
      72:  
      73:         var removeFromCache = function(c, parent) {
      74:             window.lookup[parent] = window.lookup[parent] || {};
      75:  
      76:             var ctrl = window.lookup[parent][c];
      77:             delete window.lookup[parent][c];
      78:             if (ctrl) {
      79:                 if (ctrl.view) {
      80:                     clean(ctrl.view, true);
      81:                 }
      82:                 ctrl.destroy();
      83:             }
      84:         };
      85:  
      86:         var loadLevel = function(expander, record, body, row) {
      87:             if (body.rendered) {
      88:                 return;
      89:             }
      90:             var recId = record.id,
      91:                 gridId = expander.grid.id,
      92:                 level = record.data.Level;
      93:             Ext.net.DirectMethods.BuildGrid(level + 1, recId, gridId, {
      94:                 eventMask: {
      95:                     showMask: true,
      96:                     tartget: "customtarget",
      97:                     customTarget: expander.grid.body
      98:                 },
      99:  
     100:                 success: function() {
     101:                     body.rendered = true;
     102:                 },
     103:  
     104:                 failure: function() {
     105:                     alert('服务器错误.');
     106:                 }
     107:             });
     108:         };
     109:  
     110:         Ext.onReady(function() {
     111:             var obj = Ext.getCmp("Params");
     112:             params.setParams();
     113:             obj.setValue(params.toJson());
     114:         });
     115:     
    </script>
     
    </head>
    <body>
        <form id="form1" runat="server">
        <ext:ResourceManager ID="ResourceManager1" runat="server" />
        <ext:Toolbar ID="Toolbar1" runat="server">
            <Items>
                <ext:Toolbar ID="Toolbar2" runat="server">
                    <Items>
                        <ext:Button ID="Button1" runat="server" Text="添加">
                            <Listeners>
                                <Click Handler="setAction('add',#{Params});" />
                            </Listeners>
                            <DirectEvents>
                                <Click OnEvent="btn_action_Click">
                                    <ExtraParams>
                                        <ext:Parameter Name="action" Value="Ext.decode(#{Params}.getValue()).action" Mode="Raw">
                                        </ext:Parameter>
                                        <ext:Parameter Name="id" Value="Ext.decode(#{Params}.getValue()).ui.id" Mode="Raw">
                                        </ext:Parameter>
                                    </ExtraParams>
                                </Click>
                            </DirectEvents>
                        </ext:Button>
                        <ext:Button ID="Button2" runat="server" Text="修改">
                            <Listeners>
                                <Click Handler="setAction('edit',#{Params});" />
                            </Listeners>
                            <DirectEvents>
                                <Click OnEvent="btn_action_Click">
                                    <ExtraParams>
                                        <ext:Parameter Name="action" Value="Ext.decode(#{Params}.getValue()).action" Mode="Raw">
                                        </ext:Parameter>
                                        <ext:Parameter Name="id" Value="Ext.decode(#{Params}.getValue()).ui.id" Mode="Raw">
                                        </ext:Parameter>
                                    </ExtraParams>
                                </Click>
                            </DirectEvents>
                        </ext:Button>
                        <ext:Button ID="Button3" runat="server" Text="删除">
                            <Listeners>
                                <Click Handler="setAction('del',#{Params});" />
                            </Listeners>
                            <DirectEvents>
                                <Click OnEvent="btn_action_Click">
                                    <ExtraParams>
                                        <ext:Parameter Name="action" Value="Ext.decode(#{Params}.getValue()).action" Mode="Raw">
                                        </ext:Parameter>
                                        <ext:Parameter Name="id" Value="Ext.decode(#{Params}.getValue()).ui.id" Mode="Raw">
                                        </ext:Parameter>
                                    </ExtraParams>
                                </Click>
                            </DirectEvents>
                        </ext:Button>
                    </Items>
                </ext:Toolbar>
            </Items>
        </ext:Toolbar>
        <ext:Hidden ID="Params" runat="server" Text="">
        </ext:Hidden>
        </form>
    </body>
    </html>

    说明:

    1,自定义两个类:params 和 gridUIParams,用来保存从Grid上获得的相关数据,如当前选择的行ID等,已经当前页面要进行的操作,如add、del 和 edit。

    2,定义两个脚本方法 selectedRow 和 setAction,分别用来将从Grid上获得的相关信息,保存到隐藏域;以及将当前页面的操作保存到隐藏域。

    3,onReady 里的代码,用来初始化隐藏域的内容。

    4,方法 clean、addToCache、removeFromCache 和 loadLevel 是创建多级 Grid 的相关客户端方法。其中,loadLevel 方法通过Ext.net.DirectMethods,直接调用服务器端方法,以异步方式创建多级 Grid。

    接下来,看看后台代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Data;
    using Ext.Net;
    using Ext.Net.Utilities;
     
    namespace ExtNetMultiGridPanel
    {
        public partial class _Default : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!X.IsAjaxRequest)
                {
                    this.MultiLevel = 4;
                }
                else
                {
                    return;
                }
                this.BuildGrid(1, "r0", "r0");
            }
            protected void btn_action_Click(object sender, DirectEventArgs e)
            {
                string id = string.Empty;
                string action = string.Empty;
                if (e.ExtraParams["id"] != null) id = e.ExtraParams["id"].Trim().ToString();
                if (e.ExtraParams["action"] != null) action = e.ExtraParams["action"].Trim().ToString();
     
     
                string currentAction = string.Empty;
                switch (action)
                {
                    case "add": currentAction = "添加"; break;
                    case "edit": currentAction = "编辑"; break;
                    case "del": currentAction = "删除"; break;
                }
                string currentSelect = id.Trim().Length > 0 ? "选择行ID=" + id : "未选择行。";
                X.Js.Alert("操作:" + currentAction + ";" + currentSelect);
                // TODO
            }
            [DirectMethod]
            public void BuildGrid(int level, string recId, string gridId)
            {
                DataTable dt = DS.GetDataSource();
                DataSet ds = new DataSet();
                if (level == 1)
                {
                    ds.Merge(dt.Select("parentid=-1"));
                    dt = ds.Tables[0];
                }
                else
                {
                    DataRow[] drs = dt.Select("parentid=" + recId);
                    if (drs.Length > 0)
                    {
                        ds.Merge(drs);
                        dt = ds.Tables[0];
                    }
                    else { dt = new DataTable(); }
     
                }
     
                if (dt != null && dt.Rows.Count > 0)
                {
                    var storeId = "L".ConcatWith(level, "_", recId, "_Store");
                    var newGridId = "L".ConcatWith(level, "_", recId, "_Grid");
     
                    // 创建  Store
                    var store = new Store { ID = storeId };
                    var reader = new JsonReader
                    {
                        IDProperty = "ID",
                        Fields = { new RecordField("ID", RecordFieldType.Int), 
                            new RecordField("PARENTID", RecordFieldType.Int), 
                            new RecordField("NAME", RecordFieldType.String) }
                    };
     
                    reader.Fields.Add(new RecordField
                    {
                        Name = "Level",
                        Convert = { Handler = "return ".ConcatWith(level, ";") }
                    });
                    store.Reader.Add(reader);
                    store.CustomConfig.Add(new ConfigItem("level", level.ToString(), ParameterMode.Raw));
     
                    // 创建  GridPanel
                    var grid = new GridPanel
                    {
                        ID = newGridId,
                        Store = { 
                                        store
                                     },
                        AutoHeight = true,
                        HideHeaders = false,
                        ColumnModel =
                        {
                            Columns = { new Ext.Net.Column { Header = "标识", DataIndex = "ID" },
                                        new Ext.Net.Column {Header="父标识",DataIndex="PARENTID"},
                                        new Ext.Net.Column {Header="名称",DataIndex="NAME"}
                            }
                        }
                    };
                    // 创建  GridView
                    var view = new Ext.Net.GridView
                    {
                        ID = newGridId + "_View",
                        ForceFit = true
                    };
                    grid.View.Add(view);
     
                    // 创建 RowSelectionModel
                    var sm = new RowSelectionModel { ID = newGridId + "_SM", SingleSelect = true };
                    sm.Listeners.RowSelect.Handler = "selectedRow(" + "record.id," + level + ",#{Params});";
                    grid.SelectionModel.Add(sm);
     
                    // 创建 BeforeExpand, except last (last level is 5)
                    if (level <= this.MultiLevel)
                    {
                        view.Listeners.BeforeRefresh.Fn = "clean";
                        var re = new RowExpander
                        {
                            ID = newGridId + "_RE",
                            EnableCaching = true,
                            Template = { ID = newGridId + "_TPL", Html = "<div id=\"row" + level + "_{ID}\" style=\"background-color:white;\"></div>" }
                        };
     
                        re.Listeners.BeforeExpand.Fn = "loadLevel";
     
                        grid.Plugins.Add(re);
                    }
     
                    store.DataSource = dt;
                    store.DataBind();
     
                    if (level == 1)
                    {
                        grid.AutoHeight = true;
                        grid.AutoWidth = true;
                        this.Form.Controls.Add(grid);
     
                        grid.Plugins.Add(new PanelResizer());
                    }
                    else
                    {
                        var renderEl = "row" + (level - 1) + "_" + recId;
                        X.Get(renderEl).SwallowEvent(new string[] { "click", "mousedown", "mouseup", "dblclick" }, true);
     
                        this.RemoveFromCache(newGridId, gridId);
                        grid.Render(renderEl, RenderMode.RenderTo);
                        this.AddToCache(newGridId, gridId);
                    }
                }
            }
            /// <summary>
            /// GridPanel 的级别
            /// </summary>
            /// <remarks>
            /// 默认值为1,最大为4。即 GridPanel 默认为1级,最大4级
            /// </remarks>
            protected int MultiLevel
            {
                get
                {
                    if (this.ViewState["MultiLevel"] != null)
                    {
                        if (Convert.ToInt16(this.ViewState["MultiLevel"].ToString()) <= 4)
                            return Convert.ToInt16(this.ViewState["MultiLevel"].ToString());
                        else return 4;
                    }
                    return 1;
                }
                set
                {
                    this.ViewState["MultiLevel"] = value;
                }
            }
            /// <summary>
            /// 清除缓存
            /// </summary>
            /// <param name="id">子GridPanel的ID</param>
            /// <param name="parentId">父GridPanel的ID</param>
            private void RemoveFromCache(string id, string parentId)
            {
                X.ResourceManager.AddScript("removeFromCache({0}, {1});", JSON.Serialize(id), JSON.Serialize(parentId));
            }
            /// <summary>
            /// 添加缓存
            /// </summary>
            /// <param name="id">子GridPanel的ID</param>
            /// <param name="parentId">父GridPanel的ID</param>
            private void AddToCache(string id, string parentId)
            {
                X.ResourceManager.AddScript("addToCache({0}, {1});", JSON.Serialize(id), JSON.Serialize(parentId));
            }
        }
    }

    下载 Demo

  • 相关阅读:
    C#数组添加元素
    C#数组排序方法
    C#遍历数组
    C#动态数组ArrayList
    C#传递数组参数
    基础题(四)
    基础题(三)
    CMDB概述(二)
    CMDB概述(一)
    Django(基础篇)
  • 原文地址:https://www.cnblogs.com/liuning8023/p/2197175.html
Copyright © 2011-2022 走看看