轉(zhuǎn)帖|行業(yè)資訊|編輯:龔雪|2022-11-18 11:01:11.203|閱讀 313 次
概述:本文將為大家介紹如何用DevExpress控件實(shí)現(xiàn)多層級(jí)的數(shù)據(jù)展示,歡迎下載相關(guān)組件體驗(yàn)!
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關(guān)鏈接:
在一些應(yīng)用場(chǎng)景中,我們需要實(shí)現(xiàn)多層級(jí)的數(shù)據(jù)表格顯示,如常規(guī)的二級(jí)主從表數(shù)據(jù)展示,甚至也有多個(gè)層級(jí)展示的需求,那么我們?nèi)绾瓮ㄟ^DevExpress的GridControl控表格件實(shí)現(xiàn)這種業(yè)務(wù)需求呢?本篇隨筆基于這個(gè)需求,對(duì)二級(jí)、三級(jí)的主從表數(shù)據(jù)進(jìn)行展示,從而揭開對(duì)多層級(jí)數(shù)據(jù)展示的神秘面紗。
PS:給大家推薦這個(gè)WinForm應(yīng)用界面開發(fā)組件——DevExpress WinForms,它能完美構(gòu)建流暢、美觀且易于使用的應(yīng)用程序,無論是Office風(fēng)格的界面,還是分析處理大批量的業(yè)務(wù)數(shù)據(jù),它都能輕松勝任!
主從表數(shù)據(jù),我們知道,一個(gè)主表記錄里面關(guān)聯(lián)有多條明細(xì)從表記錄,在數(shù)據(jù)定義的層次上我們體現(xiàn)如下所示。
先定義一個(gè)實(shí)體類信息作為載體。
/// <summary> /// 記錄基礎(chǔ)信息 /// </summary> public class DetailInfo { public DetailInfo() { this.ID = Guid.NewGuid().ToString(); } /// <summary> /// ID標(biāo)識(shí) /// </summary> public string ID { get; set; } /// <summary> /// 名稱 /// </summary> public string Name { get; set; } /// <summary> /// 描述信息 /// </summary> public string Description { get; set; } }
然后主從表的數(shù)據(jù)實(shí)體類就是除了包含這些信息外,再包含一個(gè)子列表(列表信息不一定是同一個(gè)實(shí)體類),如下所示。
/// <summary> /// 二級(jí)層次的列表 /// </summary> public class Detail2Result : DetailInfo { public List<DetailInfo> Detail2List { get; set; } }
這個(gè)是我們使用繼承關(guān)系簡(jiǎn)化了信息的定義,就是這個(gè)實(shí)體類包含主表信息外,還包含一個(gè)列表集合,屬于從表數(shù)據(jù)的。
有了這些數(shù)據(jù)的定義,我們構(gòu)建一些測(cè)試的數(shù)據(jù),如下所示。
//創(chuàng)建測(cè)試數(shù)據(jù) var result = new Detail2Result() { Name = "測(cè)試", Description = "描述內(nèi)容", Detail2List = new List<DetailInfo>() { new DetailInfo() { Name = "111測(cè)試", Description = "111描述內(nèi)容" }, new DetailInfo() { Name = "222測(cè)試", Description = "222描述內(nèi)容" }, new DetailInfo() { Name = "333測(cè)試", Description = "333描述內(nèi)容" } } }; //構(gòu)造一個(gè)記錄的集合 var list = new List<Detail2Result>() { result };
這樣我們就構(gòu)建了一個(gè)主表從表記錄的數(shù)據(jù)源,可以用于表格控件的綁定的了。
首先我們?cè)诮?面上創(chuàng)建一個(gè)空白的窗體用于演示,并在窗體上增加一個(gè)GridControl控件用于展示主從表的數(shù)據(jù),如下界面所示。
然后,我們可以通過代碼創(chuàng)建我們需要的視圖信息,如創(chuàng)建主表的GridView顯示如下所示。
/// <summary> /// 創(chuàng)建第一個(gè)視圖 /// </summary> private void CreateGridView() { var grv = this.gridView1; //創(chuàng)建從表顯示的列 grv.Columns.Clear(); grv.CreateColumn("ID", "ID");//.Visible = false; grv.CreateColumn("Name", "名稱"); grv.CreateColumn("Description", "描述內(nèi)容"); grv.OptionsBehavior.ReadOnly = false; grv.OptionsBehavior.Editable = true; }
很簡(jiǎn)單,我們創(chuàng)建幾個(gè)列,并指定它的Caption中文顯示屬性就可以了,然后我們接著還需要?jiǎng)?chuàng)建從表的GridView顯示數(shù)據(jù),這個(gè)是這篇隨筆的關(guān)鍵。
具體的代碼一次性貼出來,如下所示。
GridView grv2 = null; /// <summary> /// 創(chuàng)建第二個(gè)視圖 /// </summary> private void CreateLevelView() { var grv = this.gridView1; var gridControl = this.gridControl1; //創(chuàng)建一個(gè)從表的GridView對(duì)象 grv2 = new GridView(); grv2.ViewCaption = "記錄明細(xì)"; grv2.Name = "grv2"; grv2.GridControl = gridControl; //構(gòu)建GridLevelNode并添加到LevelTree集合里面 var node = new GridLevelNode(); node.LevelTemplate = grv2; node.RelationName = "Detail2List";//這里對(duì)應(yīng)集合的屬性名稱 gridControl.LevelTree.Nodes.AddRange(new GridLevelNode[] { node }); //添加對(duì)應(yīng)的視圖集合顯示 gridControl.ViewCollection.Clear(); gridControl.ViewCollection.AddRange(new BaseView[] { grv, grv2 }); //創(chuàng)建從表顯示的列 grv2.Columns.Clear(); grv2.CreateColumn("ID", "ID"); grv2.CreateColumn("Name", "名稱"); grv2.CreateColumn("Description", "描述內(nèi)容"); //設(shè)置非只讀、可編輯 grv2.OptionsBehavior.ReadOnly = false; grv2.OptionsBehavior.Editable = true; }
我們這里注意到 GridLevelNode 對(duì)象,它是我們主從表節(jié)點(diǎn)的關(guān)鍵信息,我們需要了解下面部分的代碼:
//構(gòu)建GridLevelNode并添加到LevelTree集合里面 var node = new GridLevelNode(); node.LevelTemplate = grv2; node.RelationName = "Detail2List";//這里對(duì)應(yīng)集合的屬性名稱 gridControl.LevelTree.Nodes.AddRange(new GridLevelNode[] { node });
首先是創(chuàng)建一個(gè)節(jié)點(diǎn),然后指定它的 LevelTemplate 為我們新建的GridView,并且他的子集合對(duì)象名稱為 Detail2List ,最后把這個(gè)節(jié)點(diǎn)的信息加入到 gridControl.LevelTree.Nodes 里面就可以了,其他的代碼就和第一步差不多,指定顯示的列和中文顯示名稱即可。
還有就是我們需要把創(chuàng)建的GridView 加入到指定的集合里面。
//添加對(duì)應(yīng)的視圖集合顯示 gridControl.ViewCollection.Clear(); gridControl.ViewCollection.AddRange(new BaseView[] { grv, grv2 });
到這里基本上就是大功告成了,剩下的就是數(shù)據(jù)的綁定處理了。前面我們已經(jīng)介紹了實(shí)體類的準(zhǔn)備工作和創(chuàng)建測(cè)試數(shù)據(jù)的代碼,那么我們這里沿用上面的代碼進(jìn)行數(shù)據(jù)的綁定就可以了。如下代碼所示。
/// <summary> /// 綁定數(shù)據(jù)源 /// </summary> private void BindData() { //創(chuàng)建測(cè)試數(shù)據(jù) var result = new Detail2Result() { Name = "測(cè)試", Description = "描述內(nèi)容", Detail2List = new List<DetailInfo>() { new DetailInfo() { Name = "111測(cè)試", Description = "111描述內(nèi)容" }, new DetailInfo() { Name = "222測(cè)試", Description = "222描述內(nèi)容" }, new DetailInfo() { Name = "333測(cè)試", Description = "333描述內(nèi)容" } } }; //構(gòu)造一個(gè)記錄的集合 var list = new List<Detail2Result>() { result }; //綁定數(shù)據(jù)源 this.gridControl1.DataSource = list; } private void FrmTestDetails_Load(object sender, EventArgs e) { BindData(); }
我們來運(yùn)行下完成的程序界面,可以看到例子的效果界面如下所示。
我們可以看到數(shù)據(jù)記錄是有樹形節(jié)點(diǎn)的,展開就可以看到明細(xì)記錄了,這個(gè)就是我們這里介紹的二級(jí)主從表數(shù)據(jù)的展示效果。
上面介紹了二級(jí)主從表的數(shù)據(jù)展示,其實(shí)GridControl可以用于展示三級(jí)以及更多層級(jí)的數(shù)據(jù)展示,只要你的數(shù)據(jù)設(shè)計(jì)合理,就可實(shí)現(xiàn)多層級(jí)的正確展示的。
本小節(jié)介紹三級(jí)的主從表數(shù)據(jù)展示,和二級(jí)數(shù)據(jù)展示類似,不過我們進(jìn)一步實(shí)現(xiàn)了多層級(jí)的處理而已。
我們?cè)诙?jí)層次的數(shù)據(jù)上定義了一個(gè)三級(jí)層次的數(shù)據(jù)實(shí)體類,如下所示。
/// <summary> /// 二級(jí)層次的列表 /// </summary> public class Detail2Result : DetailInfo { public List<DetailInfo> Detail2List { get; set; } } /// <summary> /// 三級(jí)層次的列表 /// </summary> public class Detail3Result : DetailInfo { public List<Detail2Result> Detail3List { get; set; } } 三級(jí)層次的測(cè)試數(shù)據(jù)初始化如下所示: //創(chuàng)建測(cè)試數(shù)據(jù) var result = new Detail3Result() { Name = "測(cè)試11", Description = "描述內(nèi)容11", //二級(jí)列表 Detail3List = new List<Detail2Result>() { new Detail2Result() { Name = "測(cè)試22", Description = "描述內(nèi)容22", //三級(jí)列表 Detail2List = new List<DetailInfo>() { new DetailInfo() { Name = "31測(cè)試", Description = "31描述內(nèi)容" }, new DetailInfo() { Name = "32測(cè)試", Description = "32描述內(nèi)容" }, new DetailInfo() { Name = "33測(cè)試", Description = "33描述內(nèi)容" } } } } }; //構(gòu)造一個(gè)記錄的集合 var list = new List<Detail3Result>() { result }; 和二級(jí)層次的處理步驟類似,我們先創(chuàng)建主表的信息展示,如下所示。 /// <summary> /// 創(chuàng)建第一個(gè)視圖 /// </summary> private void CreateGridView() { var grv = this.gridView1; var gridControl = this.gridControl1; //創(chuàng)建從表顯示的列 grv.Columns.Clear(); grv.CreateColumn("ID", "ID");//.Visible = false; grv.CreateColumn("Name", "名稱"); grv.CreateColumn("Description", "描述內(nèi)容"); grv.OptionsBehavior.ReadOnly = false; grv.OptionsBehavior.Editable = true; }
然后著手創(chuàng)建二級(jí)、三級(jí)的列表信息展示:
GridView grv2 = null; GridView grv3 = null; /// <summary> /// 創(chuàng)建第二個(gè)視圖 /// </summary> private void CreateLevelView() { var grv = this.gridView1; var gridControl = this.gridControl1; //創(chuàng)建一個(gè)二級(jí)從表的GridView對(duì)象 grv2 = new GridView(); grv2.ViewCaption = "記錄明細(xì)"; grv2.Name = "grv2"; grv2.GridControl = gridControl; //創(chuàng)建一個(gè)三級(jí)從表的GridView對(duì)象 grv3 = new GridView(); grv3.ViewCaption = "記錄明細(xì)2"; grv3.Name = "grv3"; grv3.GridControl = gridControl;
這樣我們相當(dāng)于創(chuàng)建多兩個(gè)(總共三個(gè)GridView對(duì)象)用于展示數(shù)據(jù)列表。
接著最為關(guān)鍵的是主從關(guān)系的節(jié)點(diǎn),我們可以簡(jiǎn)單的理解他的Node節(jié)點(diǎn)和我們樹形列表的Node處理方式類似即可。
//構(gòu)建GridLevelNode var topNode = new GridLevelNode(); topNode.LevelTemplate = grv2; //這里是對(duì)應(yīng)的視圖 topNode.RelationName = "Detail3List"; //這里對(duì)應(yīng)集合的屬性名稱 //構(gòu)建GridLevelNode var secondNode = new GridLevelNode(); secondNode.LevelTemplate = grv3; //這里是對(duì)應(yīng)的視圖 secondNode.RelationName = "Detail2List";//這里對(duì)應(yīng)集合的屬性名稱 //需要添加節(jié)點(diǎn)的層級(jí)關(guān)系,類似Tree節(jié)點(diǎn)處理 topNode.Nodes.Add(secondNode); //最后添加節(jié)點(diǎn)到集合里面 gridControl.LevelTree.Nodes.Add(topNode);
通過定義兩個(gè)GridLevelNode,然后指定他們的Node關(guān)系( topNode.Nodes.Add(secondNode) ),這樣我們就可以很清晰的關(guān)聯(lián)起來它們的節(jié)點(diǎn)關(guān)系了。
最后是把我們創(chuàng)建的幾個(gè)視圖加入到集合里面,并設(shè)定一些關(guān)系即可。
//添加對(duì)應(yīng)的視圖集合顯示 gridControl.ViewCollection.Clear(); gridControl.ViewCollection.AddRange(new BaseView[] { grv, grv2, grv3 }); //創(chuàng)建從表顯示的列 grv2.Columns.Clear(); grv2.CreateColumn("ID", "ID"); grv2.CreateColumn("Name", "名稱"); grv2.CreateColumn("Description", "描述內(nèi)容"); //創(chuàng)建從表顯示的列 grv3.Columns.Clear(); grv3.CreateColumn("ID", "ID"); grv3.CreateColumn("Name", "名稱"); grv3.CreateColumn("Description", "描述內(nèi)容"); //設(shè)置非只讀、可編輯 grv2.OptionsBehavior.ReadOnly = false; grv2.OptionsBehavior.Editable = true; //設(shè)置非只讀、可編輯 grv3.OptionsBehavior.ReadOnly = false; grv3.OptionsBehavior.Editable = true; 整個(gè)部分的代碼如下所示。 GridView grv2 = null; GridView grv3 = null; /// <summary> /// 創(chuàng)建第二個(gè)視圖 /// </summary> private void CreateLevelView() { var grv = this.gridView1; var gridControl = this.gridControl1; //創(chuàng)建一個(gè)二級(jí)從表的GridView對(duì)象 grv2 = new GridView(); grv2.ViewCaption = "記錄明細(xì)"; grv2.Name = "grv2"; grv2.GridControl = gridControl; //創(chuàng)建一個(gè)三級(jí)從表的GridView對(duì)象 grv3 = new GridView(); grv3.ViewCaption = "記錄明細(xì)2"; grv3.Name = "grv3"; grv3.GridControl = gridControl; //構(gòu)建GridLevelNode var topNode = new GridLevelNode(); topNode.LevelTemplate = grv2; //這里是對(duì)應(yīng)的視圖 topNode.RelationName = "Detail3List"; //這里對(duì)應(yīng)集合的屬性名稱 //構(gòu)建GridLevelNode var secondNode = new GridLevelNode(); secondNode.LevelTemplate = grv3; //這里是對(duì)應(yīng)的視圖 secondNode.RelationName = "Detail2List";//這里對(duì)應(yīng)集合的屬性名稱 //需要添加節(jié)點(diǎn)的層級(jí)關(guān)系,類似Tree節(jié)點(diǎn)處理 topNode.Nodes.Add(secondNode); //最后添加節(jié)點(diǎn)到集合里面 gridControl.LevelTree.Nodes.Add(topNode); //添加對(duì)應(yīng)的視圖集合顯示 gridControl.ViewCollection.Clear(); gridControl.ViewCollection.AddRange(new BaseView[] { grv, grv2, grv3 }); //創(chuàng)建從表顯示的列 grv2.Columns.Clear(); grv2.CreateColumn("ID", "ID"); grv2.CreateColumn("Name", "名稱"); grv2.CreateColumn("Description", "描述內(nèi)容"); //創(chuàng)建從表顯示的列 grv3.Columns.Clear(); grv3.CreateColumn("ID", "ID"); grv3.CreateColumn("Name", "名稱"); grv3.CreateColumn("Description", "描述內(nèi)容"); //設(shè)置非只讀、可編輯 grv2.OptionsBehavior.ReadOnly = false; grv2.OptionsBehavior.Editable = true; //設(shè)置非只讀、可編輯 grv3.OptionsBehavior.ReadOnly = false; grv3.OptionsBehavior.Editable = true; } 也就是我們?cè)诖绑w初始化的時(shí)候,創(chuàng)建它們的視圖關(guān)系即可,如下代碼所示。 /// <summary> /// 測(cè)試三級(jí)主從明細(xì)列表 /// </summary> public partial class FrmTestDetails2 : BaseForm { public FrmTestDetails2() { InitializeComponent(); CreateGridView(); CreateLevelView(); }
最后就是數(shù)據(jù)源的綁定操作了,這個(gè)利用前面介紹過的準(zhǔn)備數(shù)據(jù)即可。
private void FrmTestDetails2_Load(object sender, EventArgs e) { BindData(); } /// <summary> /// 綁定數(shù)據(jù)源 /// </summary> private void BindData() { //創(chuàng)建測(cè)試數(shù)據(jù) var result = new Detail3Result() { Name = "測(cè)試11", Description = "描述內(nèi)容11", //二級(jí)列表 Detail3List = new List<Detail2Result>() { new Detail2Result() { Name = "測(cè)試22", Description = "描述內(nèi)容22", //三級(jí)列表 Detail2List = new List<DetailInfo>() { new DetailInfo() { Name = "31測(cè)試", Description = "31描述內(nèi)容" }, new DetailInfo() { Name = "32測(cè)試", Description = "32描述內(nèi)容" }, new DetailInfo() { Name = "33測(cè)試", Description = "33描述內(nèi)容" } } } } }; //構(gòu)造一個(gè)記錄的集合 var list = new List<Detail3Result>() { result }; //綁定數(shù)據(jù)源 this.gridControl1.DataSource = list; }
以上就是三級(jí)層次的關(guān)系處理,如果我們理解了,其他更多層級(jí)的數(shù)據(jù)展示也是依照這個(gè)規(guī)則,增加節(jié)點(diǎn)和視圖即可,原理一樣。
案例的效果如下所示。
上面的兩個(gè)案例是基于DevExpress的內(nèi)置表格控件GridControl進(jìn)行處理的,我們?cè)赪inform框架的開發(fā)過程中,往往為了效率和分頁方便,一般都是使用分頁控件來展示數(shù)據(jù)的,那么利用分頁控件實(shí)現(xiàn)多層級(jí)的數(shù)據(jù)展示是如何的呢?
其實(shí)基本步驟也是差不多的,只是主表視圖使用分頁控件即可,如下所示。
/// <summary> /// 數(shù)據(jù)指定的主從表展示 /// </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;//是否設(shè)置為自動(dòng)調(diào)整寬度,false為不設(shè)置 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; //創(chuàng)建一個(gè)從表的GridView對(duì)象 grv2 = new GridView(); grv2.ViewCaption = "記錄明細(xì)"; grv2.Name = "grv2"; grv2.GridControl = gridControl; //構(gòu)建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 }); //創(chuàng)建從表顯示的列 grv2.Columns.Clear(); grv2.CreateColumn("ID", "ID").Visible =false; //標(biāo)識(shí)行的關(guān)鍵字,可用于刪除處理 grv2.CreateColumn("DictType_ID", "DictType_ID").Visible = false;//創(chuàng)建一個(gè)字段,隱藏的,存儲(chǔ)記錄 grv2.CreateColumn("Name", "項(xiàng)目名稱"); grv2.CreateColumn("Value", "項(xiàng)目值"); grv2.CreateColumn("Seq", "排序"); grv2.CreateColumn("Remark", "備注"); grv2.OptionsBehavior.ReadOnly = false; grv2.OptionsBehavior.Editable = true; grv2.DataSourceChanged += grv2_DataSourceChanged; }
以上就是基于GridControl實(shí)現(xiàn)數(shù)據(jù)的主從關(guān)系的處理,可以實(shí)現(xiàn)多層級(jí)的展示,希望這些案例能夠?qū)δ阏故緮?shù)據(jù)有所幫助。
本文轉(zhuǎn)載自:
DevExpress技術(shù)交流群6:600715373 歡迎一起進(jìn)群討論
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自: