在一些應用場景中,我們需要實現多層級的數據表格顯示,如常規的二級主從表數據展示,甚至也有多個層級展示的需求,那么我們如何通過DevExpress的GridControl控表格件實現這種業務需求呢?本篇隨筆基於這個需求,對二級、三級的主從表數據進行展示,從而揭開對多層級數據展示的神秘面紗。
1、二級主從表數據展示
主從表數據,我們知道,一個主表記錄里面關聯有多條明細從表記錄,在數據定義的層次上我們體現如下所示。
先定義一個實體類信息作為載體。
/// <summary> /// 記錄基礎信息 /// </summary> public class DetailInfo { public DetailInfo() { 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; } }
然后主從表的數據實體類就是除了包含這些信息外,再包含一個子列表(列表信息不一定是同一個實體類),如下所示。
/// <summary> /// 二級層次的列表 /// </summary> public class Detail2Result : DetailInfo { public List<DetailInfo> Detail2List { get; set; } }
這個是我們使用繼承關系簡化了信息的定義,就是這個實體類包含主表信息外,還包含一個列表集合,屬於從表數據的。
有了這些數據的定義,我們構建一些測試的數據,如下所示。
//創建測試數據 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 };
這樣我們就構建了一個主表從表記錄的數據源,可以用於表格控件的綁定的了。
首先我們在界面上創建一個空白的窗體用於演示,並在窗體上增加一個GridControl控件用於展示主從表的數據,如下界面所示。
然后,我們可以通過代碼創建我們需要的視圖信息,如創建主表的GridView顯示如下所示。
/// <summary> /// 創建第一個視圖 /// </summary> private void CreateGridView() { var grv = this.gridView1; //創建從表顯示的列 grv.Columns.Clear(); grv.CreateColumn("ID", "ID");//.Visible = false; grv.CreateColumn("Name", "名稱"); grv.CreateColumn("Description", "描述內容"); grv.OptionsBehavior.ReadOnly = false; grv.OptionsBehavior.Editable = true; }
很簡單,我們創建幾個列,並指定它的Caption中文顯示屬性就可以了,然后我們接着還需要創建從表的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; }
我們這里注意到 GridLevelNode 對象,它是我們主從表節點的關鍵信息,我們需要了解下面部分的代碼
//構建GridLevelNode並添加到LevelTree集合里面 var node = new GridLevelNode(); node.LevelTemplate = grv2; node.RelationName = "Detail2List";//這里對應集合的屬性名稱 gridControl.LevelTree.Nodes.AddRange(new GridLevelNode[] { node });
首先是創建一個節點,然后指定它的 LevelTemplate 為我們新建的GridView,並且他的子集合對象名稱為 Detail2List ,最后把這個節點的信息加入到 gridControl.LevelTree.Nodes 里面就可以了,其他的代碼就和第一步差不多,指定顯示的列和中文顯示名稱即可。
還有就是我們需要把創建的GridView 加入到指定的集合里面。
//添加對應的視圖集合顯示 gridControl.ViewCollection.Clear(); gridControl.ViewCollection.AddRange(new BaseView[] { grv, grv2 });
到這里基本上就是大功告成了,剩下的就是數據的綁定處理了。前面我們已經介紹了實體類的准備工作和創建測試數據的代碼,那么我們這里沿用上面的代碼進行數據的綁定就可以了。如下代碼所示。
/// <summary> /// 綁定數據源 /// </summary> private void BindData() { //創建測試數據 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 }; //綁定數據源 this.gridControl1.DataSource = list; } private void FrmTestDetails_Load(object sender, EventArgs e) { BindData(); }
我們來運行下完成的程序界面,可以看到例子的效果界面如下所示。
我們可以看到數據記錄是有樹形節點的,展開就可以看到明細記錄了,這個就是我們這里介紹的二級主從表數據的展示效果。
2、三級主從表數據展示
上面介紹了二級主從表的數據展示,其實GridControl可以用於展示三級以及更多層級的數據展示,只要你的數據設計合理,就可實現多層級的正確展示的。
本小節介紹三級的主從表數據展示,和二級數據展示類似,不過我們進一步實現了多層級的處理而已。
我們在二級層次的數據上定義了一個三級層次的數據實體類,如下所示。
/// <summary> /// 二級層次的列表 /// </summary> public class Detail2Result : DetailInfo { public List<DetailInfo> Detail2List { get; set; } } /// <summary> /// 三級層次的列表 /// </summary> public class Detail3Result : DetailInfo { public List<Detail2Result> Detail3List { get; set; } }
三級層次的測試數據初始化如下所示:
//創建測試數據 var result = new Detail3Result() { Name = "測試11", Description = "描述內容11", //二級列表 Detail3List = new List<Detail2Result>() { new Detail2Result() { Name = "測試22", Description = "描述內容22", //三級列表 Detail2List = new List<DetailInfo>() { new DetailInfo() { Name = "31測試", Description = "31描述內容" }, new DetailInfo() { Name = "32測試", Description = "32描述內容" }, new DetailInfo() { Name = "33測試", Description = "33描述內容" } } } } }; //構造一個記錄的集合 var list = new List<Detail3Result>() { result };
和二級層次的處理步驟類似,我們先創建主表的信息展示,如下所示。
/// <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 grv2 = null; GridView grv3 = 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; //創建一個三級從表的GridView對象 grv3 = new GridView(); grv3.ViewCaption = "記錄明細2"; grv3.Name = "grv3"; grv3.GridControl = gridControl;
這樣我們相當於創建多兩個(總共三個GridView對象)用於展示數據列表。
接着最為關鍵的是主從關系的節點,我們可以簡單的理解他的Node節點和我們樹形列表的Node處理方式類似即可。
//構建GridLevelNode var topNode = new GridLevelNode(); topNode.LevelTemplate = grv2; //這里是對應的視圖 topNode.RelationName = "Detail3List"; //這里對應集合的屬性名稱 //構建GridLevelNode var secondNode = new GridLevelNode(); secondNode.LevelTemplate = grv3; //這里是對應的視圖 secondNode.RelationName = "Detail2List";//這里對應集合的屬性名稱 //需要添加節點的層級關系,類似Tree節點處理 topNode.Nodes.Add(secondNode); //最后添加節點到集合里面 gridControl.LevelTree.Nodes.Add(topNode);
通過定義兩個GridLevelNode,然后指定他們的Node關系( topNode.Nodes.Add(secondNode) ),這樣我們就可以很清晰的關聯起來它們的節點關系了。
最后是把我們創建的幾個視圖加入到集合里面,並設定一些關系即可。
//添加對應的視圖集合顯示 gridControl.ViewCollection.Clear(); gridControl.ViewCollection.AddRange(new BaseView[] { grv, grv2, grv3 }); //創建從表顯示的列 grv2.Columns.Clear(); grv2.CreateColumn("ID", "ID"); grv2.CreateColumn("Name", "名稱"); grv2.CreateColumn("Description", "描述內容"); //創建從表顯示的列 grv3.Columns.Clear(); grv3.CreateColumn("ID", "ID"); grv3.CreateColumn("Name", "名稱"); grv3.CreateColumn("Description", "描述內容"); //設置非只讀、可編輯 grv2.OptionsBehavior.ReadOnly = false; grv2.OptionsBehavior.Editable = true; //設置非只讀、可編輯 grv3.OptionsBehavior.ReadOnly = false; grv3.OptionsBehavior.Editable = true;
整個部分的代碼如下所示。
GridView grv2 = null; GridView grv3 = 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; //創建一個三級從表的GridView對象 grv3 = new GridView(); grv3.ViewCaption = "記錄明細2"; grv3.Name = "grv3"; grv3.GridControl = gridControl; //構建GridLevelNode var topNode = new GridLevelNode(); topNode.LevelTemplate = grv2; //這里是對應的視圖 topNode.RelationName = "Detail3List"; //這里對應集合的屬性名稱 //構建GridLevelNode var secondNode = new GridLevelNode(); secondNode.LevelTemplate = grv3; //這里是對應的視圖 secondNode.RelationName = "Detail2List";//這里對應集合的屬性名稱 //需要添加節點的層級關系,類似Tree節點處理 topNode.Nodes.Add(secondNode); //最后添加節點到集合里面 gridControl.LevelTree.Nodes.Add(topNode); //添加對應的視圖集合顯示 gridControl.ViewCollection.Clear(); gridControl.ViewCollection.AddRange(new BaseView[] { grv, grv2, grv3 }); //創建從表顯示的列 grv2.Columns.Clear(); grv2.CreateColumn("ID", "ID"); grv2.CreateColumn("Name", "名稱"); grv2.CreateColumn("Description", "描述內容"); //創建從表顯示的列 grv3.Columns.Clear(); grv3.CreateColumn("ID", "ID"); grv3.CreateColumn("Name", "名稱"); grv3.CreateColumn("Description", "描述內容"); //設置非只讀、可編輯 grv2.OptionsBehavior.ReadOnly = false; grv2.OptionsBehavior.Editable = true; //設置非只讀、可編輯 grv3.OptionsBehavior.ReadOnly = false; grv3.OptionsBehavior.Editable = true; }
也就是我們在窗體初始化的時候,創建它們的視圖關系即可,如下代碼所示。
/// <summary> /// 測試三級主從明細列表 /// </summary> public partial class FrmTestDetails2 : BaseForm { public FrmTestDetails2() { InitializeComponent(); CreateGridView(); CreateLevelView(); }
最后就是數據源的綁定操作了,這個利用前面介紹過的准備數據即可。
private void FrmTestDetails2_Load(object sender, EventArgs e) { BindData(); } /// <summary> /// 綁定數據源 /// </summary> private void BindData() { //創建測試數據 var result = new Detail3Result() { Name = "測試11", Description = "描述內容11", //二級列表 Detail3List = new List<Detail2Result>() { new Detail2Result() { Name = "測試22", Description = "描述內容22", //三級列表 Detail2List = new List<DetailInfo>() { new DetailInfo() { Name = "31測試", Description = "31描述內容" }, new DetailInfo() { Name = "32測試", Description = "32描述內容" }, new DetailInfo() { Name = "33測試", Description = "33描述內容" } } } } }; //構造一個記錄的集合 var list = new List<Detail3Result>() { result }; //綁定數據源 this.gridControl1.DataSource = list; }
以上就是三級層次的關系處理,如果我們理解了,其他更多層級的數據展示也是依照這個規則,增加節點和視圖即可,原理一樣。
案例的效果如下所示。
3、利用分頁控件實現數據的展示
上面的兩個案例是基於DevExpress的內置表格控件GridControl進行處理的,我們在Winform框架的開發過程中,往往為了效率和分頁方便,一般都是使用分頁控件來展示數據的,那么利用分頁控件實現多層級的數據展示是如何的呢?
其實基本步驟也是差不多的,只是主表視圖使用分頁控件即可,如下所示。
/// <summary> /// 數據指定的主從表展示 /// </summary> public partial class FrmDictTypeMasterDetail : BaseDock { public FrmDictTypeMasterDetail() { InitializeComponent(); InitDictItem(); this.winGridViewPager1.OnPageChanged += new EventHandler(winGridViewPager1_OnPageChanged); this.winGridViewPager1.OnStartExport += new EventHandler(winGridViewPager1_OnStartExport); this.winGridViewPager1.OnDeleteSelected += new EventHandler(winGridViewPager1_OnDeleteSelected); this.winGridViewPager1.OnRefresh += new EventHandler(winGridViewPager1_OnRefresh); this.winGridViewPager1.AppendedMenu = this.contextMenuStrip1; this.winGridViewPager1.ShowLineNumber = true; this.winGridViewPager1.BestFitColumnWith = false;//是否設置為自動調整寬度,false為不設置 this.winGridViewPager1.gridView1.DataSourceChanged += new EventHandler(gridView1_DataSourceChanged); this.winGridViewPager1.gridView1.CustomColumnDisplayText += new DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventHandler(gridView1_CustomColumnDisplayText); this.winGridViewPager1.gridView1.RowCellStyle += new DevExpress.XtraGrid.Views.Grid.RowCellStyleEventHandler(gridView1_RowCellStyle); CreateLevelView(); RegisterEvent(); } GridView grv2 = null; private void CreateLevelView() { var grv = this.winGridViewPager1.GridView1; var gridControl = this.winGridViewPager1.gridControl1; //創建一個從表的GridView對象 grv2 = new GridView(); grv2.ViewCaption = "記錄明細"; grv2.Name = "grv2"; grv2.GridControl = gridControl; //構建GridLevelNode並添加到LevelTree集合里面 var node = new GridLevelNode(); node.LevelTemplate = grv2; node.RelationName = "Children"; gridControl.LevelTree.Nodes.AddRange(new GridLevelNode[] { node }); gridControl.ViewCollection.Clear(); gridControl.ViewCollection.AddRange(new BaseView[] { grv, grv2 }); //創建從表顯示的列 grv2.Columns.Clear(); grv2.CreateColumn("ID", "ID").Visible =false; //標識行的關鍵字,可用於刪除處理 grv2.CreateColumn("DictType_ID", "DictType_ID").Visible = false;//創建一個字段,隱藏的,存儲記錄 grv2.CreateColumn("Name", "項目名稱"); grv2.CreateColumn("Value", "項目值"); grv2.CreateColumn("Seq", "排序"); grv2.CreateColumn("Remark", "備注"); grv2.OptionsBehavior.ReadOnly = false; grv2.OptionsBehavior.Editable = true; grv2.DataSourceChanged += grv2_DataSourceChanged; }
以上就是基於GridControl實現數據的主從關系的處理,可以實現多層級的展示,希望這些案例能夠對你展示數據有所幫助。