在我早期的隨筆《在GridControl表格控件中實現多層級主從表數據的展示》中介紹過GridControl實現二級、三級的層級列表展示,主要的邏輯就是構建GridLevelNode並添加到LevelTree集合里面,手動創建多個承載顯示的gridview,然后添加到視圖集合里面去吧,不過這個是已知層級的情況下,如果是無窮級,這種手工創建視圖的方式,肯定不太適合,而且很繁瑣,我們本篇隨筆來改進一下,介紹如何實現多層級或無窮級的嵌套列表展示。
1、回顧二級、三級層級的處理
根據數據展示的定義,我們構建一些測試的數據,如下所示。
//創建測試數據 var result = new Detail2Result() { Name = "測試", Description = "描述內容", Detail2List = new List<DetailInfo>() { new DetailInfo() { Name = "111測試", Description = "111描述內容" }, new DetailInfo() { Name = "222測試", Description = "222描述內容" }, new DetailInfo() { Name = "333測試", Description = "333描述內容" } } }; //構造一個記錄的集合 var list = new List<Detail2Result>() { result };
接着通過代碼創建我們需要的視圖信息,如創建主表的GridView顯示如下所示。
GridView grv2 = null; /// <summary> /// 創建第二個視圖 /// </summary> private void CreateLevelView() { var grv = this.gridView1; var gridControl = this.gridControl1; //創建一個從表的GridView對象 grv2 = new GridView(); grv2.ViewCaption = "記錄明細"; grv2.Name = "grv2"; grv2.GridControl = gridControl; //構建GridLevelNode並添加到LevelTree集合里面 var node = new GridLevelNode(); node.LevelTemplate = grv2; node.RelationName = "Detail2List";//這里對應集合的屬性名稱 gridControl.LevelTree.Nodes.AddRange(new GridLevelNode[] { node }); //添加對應的視圖集合顯示 gridControl.ViewCollection.Clear(); gridControl.ViewCollection.AddRange(new BaseView[] { grv, grv2 }); //創建從表顯示的列 grv2.Columns.Clear(); grv2.CreateColumn("ID", "ID"); grv2.CreateColumn("Name", "名稱"); grv2.CreateColumn("Description", "描述內容"); //設置非只讀、可編輯 grv2.OptionsBehavior.ReadOnly = false; grv2.OptionsBehavior.Editable = true; }
剩下的就是數據的綁定處理了,這里構建列表,綁定數據源展示即可
//構造一個記錄的集合 var list = new List<Detail2Result>() { result }; //綁定數據源 this.gridControl1.DataSource = list;
可以看到例子的效果界面如下所示。
二級和三級處理的方式類似,就不再贅述了。
2、多層級或無窮級的嵌套列表展示
如果是不確定的多層級列表展示,那么我們應該如何處理呢,手工逐一創建視圖的方式,肯定不合適,畢竟有時候數據層次是不確定的,如下數據結構所示,它是一個嵌套的數據結構。
/// <summary> /// 本類用於演示多層級的數據列表的展示 /// </summary> public class DetailNodeInfo { public DetailNodeInfo() { this.ID = Guid.NewGuid().ToString(); } /// <summary> /// ID標識 /// </summary> public string ID { get; set; } /// <summary> /// 名稱 /// </summary> public string Name { get; set; } /// <summary> /// 描述信息 /// </summary> public string Description { get; set; } public List<DetailNodeInfo> Children { get; set; } = new List<DetailNodeInfo>();//初始化 }
這里面我們的嵌套列表使用了Children屬性。
這樣我們創建視圖的時候,只需要創建主視圖gridview即可,如下所示
/// <summary> /// 創建第一個視圖 /// </summary> private void CreateGridView() { var grv = this.gridView1; var gridControl = this.gridControl1; //創建從表顯示的列 grv.Columns.Clear(); grv.CreateColumn("ID", "ID");//.Visible = false; grv.CreateColumn("Name", "名稱"); grv.CreateColumn("Description", "描述內容"); //列表是否只讀 grv.OptionsBehavior.ReadOnly = false; //列表是否可以編輯 grv.OptionsBehavior.Editable = true; //gridview列表注冊的時候,觸發處理 gridControl.ViewRegistered += GridControl_ViewRegistered; }
其中紅色的ViewRegistered是用來觸發從表視圖的時候,我們處理列頭的中文信息的
private void GridControl_ViewRegistered(object sender, ViewOperationEventArgs e) { var detailView = e.View as GridView; if (detailView != null) { SetGridViewCaption(detailView); } } private void SetGridViewCaption(GridView view) { foreach (GridColumn column in view.Columns) { SetColumnCaption(column, "id", "編號"); SetColumnCaption(column, "name", "名稱"); SetColumnCaption(column, "name", "描述內容"); } } private void SetColumnCaption(GridColumn column, string fieldName, string caption) { if(column != null && column.FieldName.Equals(fieldName, StringComparison.OrdinalIgnoreCase)) { column.Caption = caption; } }
為了測試無窮級嵌套列表的展示,我們創建了一個多級的嵌套列表數據,如下所示。
/// <summary> /// 綁定數據源 /// </summary> private void BindData() { //創建測試數據 var result = new DetailNodeInfo() { Name = "測試1", Description = "描述內容", //二級列表 Children = new List<DetailNodeInfo>() { new DetailNodeInfo() { Name = "測試2", Description = "描述內容", //三級列表 Children = new List<DetailNodeInfo>() { new DetailNodeInfo() { Name = "3測試", Description = "描述內容", //四級列表 Children = new List<DetailNodeInfo>() { new DetailNodeInfo() { Name = "4測試", Description = "描述內容", Children = new List<DetailNodeInfo>() { new DetailNodeInfo() { Name = "5測試", Description = "描述內容", Children = null } } } } } } } } };
綁定操作代碼和之前處理沒有什么異樣。
//構造一個記錄的集合 var list = new List<DetailNodeInfo>() { result }; //綁定數據源 this.gridControl1.DataSource = list;
注意,以上列表只是展示,並沒有保存處理。
如果需要綁定可以直接錄入並保存的操作,列表必須為BindingList<T>類型,這個才能記錄狀態的,如下數據結構定義所示。
詳細可以參考我隨筆《基於主從表數據錄入的處理》 中的介紹。