ASP.NET-FineUI開發實踐-13(一)


開原版好像是沒有gird樹,有一個擴展列下的模擬樹列,就是不能展開,專業版有,開原版我弄了弄,思路是有,就是不是很好實現。這篇博客直接寫出了(一)說明一個肯定是寫不完的。

FineUI重在封裝,改這個我也不打算大量的js實現,最起碼前台傳幾個屬性就可以了,后台就都實現了,這是初衷,就是有點慢,太慢的話以后會改成前台實現的。以前我修改的或新建的不管是前后台方法都是可以通用的,盡量避免一個頁面寫一遍,那不是好代碼。
 
1.核心
對於顯示樹層級,主要的就是縮進,這個弄好了就可以了,好在列有個DataSimulateTreeLevelField屬性,根本就不用擔心,這里傳的是層級,有就傳,沒有就創造,先放着。當然不能有也只能重寫數據源,這也是樹grid慢的原因之一。
 
考慮完顯示就是考慮展開和收起,方法先不談,方法是被觸發的,這里就要靠點擊觸發展開收起方法,專業版是個箭頭,我也找了個圖標,每個行放一個,這就用到了重寫數據源,有很多地方可以寫:綁定之前,綁定之后渲染之前,行綁定事件里,也可以跟蹤DataSimulateTreeLevelField屬性,他就是加了個圖標,他怎么加的我怎么加就可以了。圖標的觸發就是jq了,其實完全可以寫成自定義事件就是給grid加個事件,這個也是后話。
 
觸發完了才是展開和收起的方法,一下就讓我想到了刪除和添加,不就是刪除指定行和添加指定行么,但是添加有難度,刪除了數據丟了我加誰,但是通過實驗我看見js執行的刪除沒有真的刪除數據源,只是把顯示的扔了,這就好辦了,重新綁一下又回來了(這個是從Demo里刪除后需要保存想到的),那么只有刪除,控制了刪除和重新載入數據源就可以實現展開了。刪除方法    store.removeAt(rowIndex); 重新載入.f_loadData(); 很容易能找到。
 
2.參數
剛說用參數實現了,看到專業版用到的參數有  是否開啟樹,樹字段的列名,樹ID,父ID
說謝謝就可以拿來用了,目前夠用了。注意我這里的樹ID和父ID不是數據源,而是列名ColumnID
        /// <summary>
        /// 是否啟用樹
        /// </summary>
        [Category(CategoryName.OPTIONS)]
        [DefaultValue(null)]
        [Description("是否啟用樹")]
        public bool EnableTree
        {
            get
            {
                object obj = FState["EnableTree"];
                return obj == null ? false : (bool)obj;
            }
            set
            {
                FState["EnableTree"] = value;
                if (value)
                {
                    EnableRowClickEvent = true;
                }
            }
        }
        /// <summary>
        /// 樹節點列名
        /// </summary>
        [Category(CategoryName.OPTIONS)]
        [DefaultValue(null)]
        [Description("樹節點列名")]
        public string TreeName
        {
            get
            {
                object obj = FState["TreeName"];
                return obj == null ? "" : (string)obj;
            }
            set
            {
                FState["TreeName"] = value;
            }
        }

        /// <summary>
        /// 主鍵ID
        /// </summary>
        [Category(CategoryName.OPTIONS)]
        [DefaultValue(null)]
        [Description("主鍵ID")]
        public string TreeDataIDField
        {
            get
            {
                object obj = FState["TreeDataIDField"];
                return obj == null ? "" : (string)obj;
            }
            set
            {
                FState["TreeDataIDField"] = value;
            }
        }
        /// <summary>
        /// 父節點列名
        /// </summary>
        [Category(CategoryName.OPTIONS)]
        [DefaultValue(null)]
        [Description("父節點列名")]
        public string TreeDataParentIDField
        {
            get
            {
                object obj = FState["TreeDataParentIDField"];
                return obj == null ? "" : (string)obj;
            }
            set
            {
                FState["TreeDataParentIDField"] = value;
            }
        }

 

3.顯示方法
首先我找到了用到DataSimulateTreeLevelField屬性的方法,方法名稱為Grid.AfterDataBind
很明顯綁定之后觸發的,好吧一切從這里開始。
意思就是如果有這樣的列,拿出來,這是我寫的
如果開着樹,列名不為空,找到列。
再往下,其實現在DataSimulateTreeLevelField是沒有值的,寫我的
得到層級方法GetLevelNub,通過什么得到呢?數據源,看我傳的參數,數據源綁定后變成了Rows,行的集合,操作這個就可以了,根本就不用考慮是DataTable還是IEnumerable
 /// <summary>
        /// 得到當然行的層級
        /// </summary>
        /// <param name="row">當前行</param>
        /// <param name="Rows">行數據集</param>
        /// <returns>層級</returns>
        private int GetLevelNub(GridRow row, GridRowCollection Rows)
        {
            int lub = 0;
            //ID所在列
            int IDindex = FindColumn(TreeDataIDField).ColumnIndex;
            //父ID所在列
            int ParentIDindex = FindColumn(TreeDataParentIDField).ColumnIndex;
            //如果過是第第一級就是0
            if (row.Values[ParentIDindex].ToString() == "" || row.Values[ParentIDindex].ToString() == "0")
            {
                return lub;
            }
            else
            {
                foreach (GridRow gr in Rows)
                {
                    //如果有父級
                    if (gr.Values[IDindex].ToString() == row.Values[ParentIDindex].ToString())
                    {
                        //層級加1
                        lub++;
                        //查看父級的父級
                        int nub = GetLevelNub(gr, Rows);
                        lub += nub == 0 ? 1 : nub;
                    }
                }
            }
            return lub;
        }
這個方法就是個邏輯的問題,循環得到父級就可以了。這里直接用TreeDataIDField就可以了,因為是參數。
這樣就可以了,先看一下下。
我新建了頁面,新建了數據源,
<f:Grid EnableCollapse="true" Width="800px" Height="400px" runat="server" DataKeyNames="Id,Name"
        ID="Grid1" EnableTree="true" TreeName="name" TreeDataIDField="id" TreeDataParentIDField="topID" ShowBorder="true"
        ShowHeader="true" Title="樹表格" >
        <Columns>
            <f:RowNumberField />
            <f:BoundField ColumnID="name" ExpandUnusedSpace="true" DataField="name" HeaderText="名稱" >
            </f:BoundField>
            <f:BoundField  ColumnID="id" DataField="id" Width="50px" HeaderText="ID">
            </f:BoundField>
            <f:BoundField  ColumnID="topID" DataField="topID" Width="50px" HeaderText="topID">
            </f:BoundField>
            <f:BoundField DataField="levelcode" Width="100px" HeaderText="層級編號">
            </f:BoundField>
            <f:BoundField ColumnID="levelnub" DataField="levelnub" Width="100px" HeaderText="層級數">
            </f:BoundField>
            <f:BoundField DataField="subitem" Width="100px" HeaderText="是否為子菜單">
            </f:BoundField>
            <f:BoundField DataField="url" Width="100px" HeaderText="地址">
            </f:BoundField>
        </Columns>
    </f:Grid>

OK縮進起效了。但是層級不對,我的下級2和28是下級1 之后的,這是由於數據源沒有按層級排序,看來要寫個通過父ID給樹結構從新排序的方法。
 
4.重新排序方法
        /// <summary>
        /// 對rows進行重新排序
        /// </summary>
        private void SortTreeRows()
        {
            GridRowCollection newrows = new GridRowCollection();
            //復制到新列表
            foreach (GridRow row in Rows)
            {
                newrows.Add(row);
            }
            //清空
            Rows.Clear();
            int pidindex = FindColumn(TreeDataParentIDField).ColumnIndex;
            int idindex = FindColumn(TreeDataIDField).ColumnIndex;
            //記錄根節點
            GridRowCollection onerows = new GridRowCollection();
            //int i = 0;
            foreach (GridRow row in newrows)
            {
                if (row.Values[pidindex].ToString() == "" || row.Values[pidindex].ToString() == "0")
                {
                    //row.RowIndex = i;
                    //i++;
                    //保存跟節點
                    Rows.Add(row);
                    onerows.Add(row);
                }
            }
            int c = onerows.Count;
            //循環根節點插入子節點
            for (int j = 0; j < c; j++)
            {
                GridRow row = onerows[j];
                //注意起始index計算,從新插入的行開始下一次插入
                BuildTree(Rows.Count - c + j, row, newrows);
            }
            for (int i = 0; i < Rows.Count; i++)
            {
                Rows[i].RowIndex = i;
            }
        }
        /// <summary>
        /// 重構行
        /// </summary>
        /// <param name="j">插入的index</param>
        /// <param name="row">當前row</param>
        /// <param name="rows">集合</param>
        private void BuildTree(int j, GridRow row, GridRowCollection rows)
        {
            //得到下層節點index
            string nexindex = GetNextIndex(row, rows);
            if (nexindex != "")
            {
                string[] s = nexindex.Split(',');
                int c = Rows.Count;
                for (int i = 0; i < s.Length; i++)
                {
                    GridRow dr = rows[Convert.ToInt32(s[i])];
                    //重新計算下一次插入的行號
                    int index = j + i + 1 + (Rows.Count - c);
                    if (Rows.Count != c)
                    {
                        index = index - 1;
                    }
                    //dr.RowIndex = index;
                    Rows.Insert(index, dr);
                    //循環子節點
                    BuildTree(index, dr, rows);
                }
            }
        }

        /// <summary>
        /// 得到下級行號
        /// </summary>
        /// <param name="row">本節點</param>
        /// <param name="Rows">集合</param>
        /// <returns>集合以,隔開</returns>
        private string GetNextIndex(GridRow row, GridRowCollection Rows)
        {
            string topindex = "";
            int pridindex = FindColumn(TreeDataParentIDField).ColumnIndex;
            int idindex = FindColumn(TreeDataIDField).ColumnIndex;
            foreach (GridRow gr in Rows)
            {
                //父ID等於本ID添加到集合
                if (gr.Values[pridindex].ToString() != "" && gr.Values[pridindex].ToString() == row.Values[idindex].ToString())
                {
                    topindex += topindex == "" ? gr.RowIndex.ToString() : "," + gr.RowIndex.ToString();
                }
            }
            return topindex;
        }
邏輯着實的復雜,大體思路是這樣滴,先把數據集復制,清空數據集,先找到第一層,Add到Rows,通過第一層找到下一層insert到第一層下,然后逐級insert插入新的子集實現排序,這個方法看着挺惡心,我腦袋也就這樣了,各位大大可以幫我寫寫。
在AfterDataBind里加上這個方法就可以了
可以看到層級正確,點擊方法明天再說。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM