在DevExpress中使用BandedGridView表格實現多行表頭的處理

来源:https://www.cnblogs.com/wuhuacong/archive/2023/05/22/17420281.html
-Advertisement-
Play Games

在之前較早隨筆中介紹過實現多行表頭的處理,通過手工創建欄位以及映射數據源欄位屬性的方式實現,有些客戶反映是否可以通過代碼方式更方便的創建對應的處理操作,因此本篇隨筆繼續探討這個多行表頭的處理的操作,使用代碼的方式結合擴展函數處理,快速的實現GridControl的多行表頭的處理操作。 ...


在之前較早隨筆中介紹過實現多行表頭的處理,通過手工創建欄位以及映射數據源欄位屬性的方式實現,有些客戶反映是否可以通過代碼方式更方便的創建對應的處理操作,因此本篇隨筆繼續探討這個多行表頭的處理的操作,使用代碼的方式結合擴展函數處理,快速的實現GridControl的多行表頭的處理操作。

1、回顧使用手工創建BandedColumn和綁定欄位列

在隨筆《DevExpress控制項開發常用要點(項目總結版)》總結了一些GridControl控制項的一些操作,其中也提到了多行表頭綁定處理,如下界面所示。

有時候,我們為了一些特殊的需要,要對錶頭進行特別的排版,使其支持多行表頭的效果,如上圖所示,這樣方便對各項內容進行歸類顯示,易於閱讀,在DevExpress中應該如何實現這個效果呢?

1)先在設計模式將普通的GridView轉換為BandedGridView或者AdvBandedGridView,這樣才能支持這種多行表頭的做法,如下所示。

2)定義一些欄位,用來顯示其中的內容,如下圖所示。

3)定義一些Band列,設置相關的屬性,並把設計界面中的欄位列表拖動到對應過的Band列上面,這樣就構成了一個Band列和欄位內容的對應關係。

完成上面的綁定關係後,記得設置GridView控制項的屬性,使其不要顯示原本的ColumnHeader等內容。

設置好這些內容,才能合理、完美顯示出多行表頭的信息。

 

2、使用代碼的方式結合擴展函數處理,快速的實現GridControl的多行表頭

上面的操作,適合於新手的一些簡單的欄位綁定處理,有時候我們為了方便,可能更傾向於使用代碼的方式快速構建多行表頭的操作。

我們通過查看代碼,可以瞭解GridBand對象是一個嵌套的關係,它類似樹形結構,可以有很多層的子集合,也就是嵌套的頭部條,它結合欄位列對象GridColumn就形成了BandedGridColumn的信息。

我們需要知道GridBand只是一個頭部的條狀列信息,一般用來覆蓋GridColumn的預設列頭信息,因此需要設置一定的樣式來禁用顯示預設的GridColumn的頭部信息。

view.OptionsView.ShowColumnHeaders = false; //因為有Band列了,所以把ColumnHeader隱藏

因此我們創建一個擴展的靜態類文件,並加入設置BandedGridView樣式的處理擴展方法,把相關的樣式統一處理,如下所示。

    /// <summary>
    /// GridView及其RepositoryItem編輯控制項的擴展類
    /// </summary>
    public static class Grid_Extension
    {
        /// <summary>
        /// 設置BandedGridView的樣式
        /// </summary>
        /// <param name="view"></param>
        public static void SetBandedViewStyle(this BandedGridView view)
        {
            view.BeginUpdate(); //開始視圖的編輯,防止觸發其他事件
            view.Bands.Clear();
            //修改附加選項
            view.OptionsView.ShowColumnHeaders = false; //因為有Band列了,所以把ColumnHeader隱藏
            view.OptionsView.ShowGroupPanel = false;    //如果沒必要分組,就把它去掉
            view.OptionsView.EnableAppearanceEvenRow = false; //是否啟用偶數行外觀
            view.OptionsView.EnableAppearanceOddRow = true;   //是否啟用奇數行外觀
            view.OptionsView.ShowFilterPanelMode = ShowFilterPanelMode.Never;   //是否顯示過濾面板
            view.OptionsCustomization.AllowColumnMoving = false;                //是否允許移動列
            view.OptionsCustomization.AllowColumnResizing = false;              //是否允許調整列寬
            view.OptionsCustomization.AllowGroup = false;                       //是否允許分組
            view.OptionsCustomization.AllowFilter = false;                      //是否允許過濾
            view.OptionsCustomization.AllowSort = true;                         //是否允許排序
            view.OptionsSelection.EnableAppearanceFocusedCell = true;           //是否焦點顯示選中的單元格           
            view.EndUpdate();   //結束視圖的編輯
        }

由於GridBand可能是嵌套的多層表頭,因此為了方便,可以單獨設置一個擴展方法創建GridBand,這樣有助於引用對象。

        /// <summary>
        /// 創建綁定Banded列
        /// </summary>
        /// <param name="view"></param>
        /// <param name="caption"></param>
        /// <param name="width"></param>
        /// <param name="fixedStyle"></param>
        /// <param name="visible">是否可見</param>
        /// <returns></returns>
        public static GridBand CreateBand(this BandedGridView view, string caption, int width = 80, FixedStyle fixedStyle = FixedStyle.None, bool visible = true)
        {
            //使用多語言處理標題
            caption = JsonLanguage.Default.GetString(caption);
            var band = new GridBand
            {
                Caption = caption,
                Width = width,
                Fixed = fixedStyle,
                Visible = visible,  
            };
            view.Bands.Add(band);
            band.VisibleIndex = view.Bands.Count;
            band.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center;
            return band;
        }

這樣我們就可以傳遞GridBand對象來構建多層級的欄位列信息了,利用擴展函數,我們可以方便的實現創建綁定列信息。

        /// <summary>
        /// 根據指定的GridBand父級對象,構建BandedGridColumn列對象
        /// </summary>
        /// <param name="view"></param>
        /// <param name="band"></param>
        /// <param name="fieldName"></param>
        /// <param name="caption"></param>
        /// <param name="allowEdit"></param>
        /// <param name="allowMerge"></param>
        /// <returns></returns>
        public static BandedGridColumn CreateBandColumn(this BandedGridView view, GridBand band, string fieldName, string caption, bool allowEdit = true, DefaultBoolean allowMerge = DefaultBoolean.False)
        {
            //使用多語言處理標題
            caption = JsonLanguage.Default.GetString(caption);
            var gridColumn = new BandedGridColumn()
            {
                FieldName = fieldName,
                Caption = caption,
                UnboundType = UnboundColumnType.Bound,
                Visible = true
            };
            band.AppearanceHeader.BackColor  = Color.LightGreen;

            var newBand = band.Children.AddBand(caption);
            newBand.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center; //文本居中
            newBand.Columns.Add(gridColumn);

            gridColumn.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center;
            gridColumn.AppearanceCell.TextOptions.VAlignment = VertAlignment.Center;

            gridColumn.OptionsColumn.AllowEdit = allowEdit;
            if (!allowEdit)
            {
                gridColumn.AppearanceHeader.ForeColor = Color.Gray;
            }

            bool allowCellMerge = !view.OptionsView.AllowCellMerge && allowMerge == DefaultBoolean.True;
            if (allowCellMerge)
            {
                view.OptionsView.AllowCellMerge = true;
            }
            gridColumn.OptionsColumn.AllowMerge = allowMerge;
            return gridColumn;
        }

而如果一般的列,沒有多層嵌套的GridBand,也就是只有一層的表頭,我們也需要根據欄位信息進行構建一個GridBandColumn來顯示信息,如下所示。

        /// <summary>
        /// 根據欄位信息,構建BandedGridColumn列對象
        /// </summary>
        /// <param name="view">視圖對象</param>
        /// <param name="fieldName">欄位名稱</param>
        /// <param name="caption">顯示名稱</param>
        /// <param name="width">列寬度</param>
        /// <param name="fixedStyle">固定顯示模式</param>
        /// <param name="visible">是否可見</param>
        /// <param name="allowEdit">是否可編輯</param>
        /// <param name="allowMerge">是否可合併</param>
        /// <param name="unboundColumnType">綁定類型,預設為UnboundColumnType.Bound</param>
        /// <returns></returns>
        public static BandedGridColumn CreateBandColumn(this BandedGridView view, string fieldName, string caption, int width = 80, FixedStyle fixedStyle = FixedStyle.None, bool visible = true, bool allowEdit = true, DefaultBoolean allowMerge = DefaultBoolean.False, UnboundColumnType unboundColumnType = UnboundColumnType.Bound)
        {
            //使用多語言處理標題
            caption = JsonLanguage.Default.GetString(caption);
            var gridColumn = new BandedGridColumn()
            {
                FieldName = fieldName,
                Caption = caption,
                Width = width,
                UnboundType = unboundColumnType,
            }; 
            var band = view.CreateBand(caption, width, fixedStyle);
            band.Visible = visible;
            band.Columns.Add(gridColumn);
            //view.Columns[fieldName].OwnerBand = band;
            gridColumn.AbsoluteIndex = view.Columns.Count;
            gridColumn.Visible = visible;//是否可見
            if (visible)
            {
                gridColumn.VisibleIndex = view.Columns.Count;
            }
            gridColumn.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center;
            gridColumn.AppearanceCell.TextOptions.VAlignment = VertAlignment.Center;

            gridColumn.OptionsColumn.AllowEdit = allowEdit;
            if (!allowEdit)
            {
                gridColumn.AppearanceHeader.ForeColor = Color.Gray;
            }
            bool allowCellMerge = !view.OptionsView.AllowCellMerge && allowMerge == DefaultBoolean.True;
            if (allowCellMerge)
            {
                view.OptionsView.AllowCellMerge = true;
            }
            gridColumn.OptionsColumn.AllowMerge = allowMerge;
            gridColumn.Fixed = fixedStyle;

            return gridColumn;
        }

有了這些擴展函數的鋪墊,我們在實際界面中展示多層級的多行表頭就會變得很容易了。為了方便介紹,我創建一個簡單的窗體用來展示多行表頭的代碼綁定處理。

創建一個預設的窗體,放置GridControl,並把預設的GridView視圖,轉換為BandedGridView視圖對象,如下所示。

為了綁定一些欄位信息供顯示、編輯處理,我們創建了一個表格,包含信息:Id,姓名,外科皮膚科_診斷,外科皮膚科_結論,神經精神科_診斷,神經精神科_結論,內科_診斷,內科_結論,眼科_診斷,眼科_結論,檢查時間,備註 等欄位內容,如下代碼所示。

            var table = DataTableHelper.CreateTable("Id|int,姓名,外科皮膚科_診斷,外科皮膚科_結論,神經精神科_診斷,神經精神科_結論,內科_診斷,內科_結論,眼科_診斷,眼科_結論,檢查時間,備註");
            
            //準備飛行員體檢測試數據
            for (int i =1; i <= 50;i++)
            {
                var dr = table.NewRow();
                dr["Id"] = i;
                dr["姓名"] = $"某某{i}";

                dr["外科皮膚科_診斷"] = "健康";
                dr["外科皮膚科_結論"] = "合格";

                dr["神經精神科_診斷"] = "健康";
                dr["神經精神科_結論"] = "合格";

                dr["內科_診斷"] = "健康";
                dr["內科_結論"] = "合格";

                dr["眼科_診斷"] = "健康";
                dr["眼科_結論"] = "合格";

                dr["檢查時間"] = DateTime.Now;
                dr["備註"] = "";

                table.Rows.Add(dr);
            }

首先需要創建GridView的初始化信息,如綁定那些欄位列,結合多表頭的處理方式,如下代碼所示。

/// <summary>
/// 初始化列表
/// </summary>
private void InitGridView()
{
    var grid = this.gridControl1;
    var grv = this.gridControl1.MainView as BandedGridView;
    grid.ContextMenuStrip = this.contextMenuStrip1;//右鍵菜單
//初始化GridView樣式,並設置相關的BandedGridView樣式
    grv.InitGridView(GridType.EditOnly, false, EditorShowMode.MouseDownFocused, "");
    grv.SetBandedViewStyle();

    //創建顯示的列:
    //Id,姓名,外科皮膚科_診斷,外科皮膚科_結論,神經精神科_診斷,神經精神科_結論,內科_診斷,內科_結論,眼科_診斷,眼科_結論,檢查時間,備註
    grv.Columns.Clear();
    grv.CreateBandColumn("Id", "Id", 80, FixedStyle.Left, true, false);
    grv.CreateBandColumn("姓名", "客戶名稱", 80, FixedStyle.Left, true, false);

    var band1 = grv.CreateBand("外科皮膚科", 120);
    grv.CreateBandColumn(band1, "外科皮膚科_診斷", "診斷");
    grv.CreateBandColumn(band1, "外科皮膚科_結論", "結論");

    var band2 = grv.CreateBand("神經精神科", 120);
    grv.CreateBandColumn(band2, "神經精神科_診斷", "診斷");
    grv.CreateBandColumn(band2, "神經精神科_結論", "結論");

    var band3 = grv.CreateBand("內科", 120);
    grv.CreateBandColumn(band3, "內科_診斷", "診斷");
    grv.CreateBandColumn(band3, "內科_結論", "結論");

    var band4 = grv.CreateBand("眼科", 120);
    grv.CreateBandColumn(band4, "眼科_診斷", "診斷");
    grv.CreateBandColumn(band4, "眼科_結論", "結論");

    var colCheckTime = grv.CreateBandColumn("檢查時間", "檢查時間").CreateDateEdit();//可修改
    colCheckTime.EditMask = "yyyy-MM-dd";
    colCheckTime.DisplayFormat.FormatString = "yyyy-MM-dd";
    colCheckTime.EditFormat.FormatString = "yyyy-MM-dd";
    colCheckTime.CustomDisplayText += (s, e) =>
    {
        if (e.Value != null && e.Value.ToString() != "")
        {
            if (Convert.ToDateTime(e.Value) <= Convert.ToDateTime("1900-1-1"))
            {
                e.DisplayText = "";
            }
            else
            {
                e.DisplayText = Convert.ToDateTime(e.Value).ToString("yyyy-MM-dd");
            }
        }
    };
    //可修改
    grv.CreateBandColumn("備註", "備註", 200);

    //設置部分欄位不可修改
    var editFields = "外科皮膚科_診斷,外科皮膚科_結論,神經精神科_診斷,神經精神科_結論,內科_診斷,內科_結論,眼科_診斷,眼科_結論,檢查時間,備註";
    grv.SetColumnsReadOnly("*", false);
    grv.SetColumnsReadOnly(editFields, true);

    //檢查輸入
    grv.ValidateRow += (s, e) =>
    {
        //校驗一些不能為空的欄位
        //var result = grid.ValidateRowNull(e, new string[]
        //{
        //    "產品編碼",
        //    "產品名稱"
        //});
    };
    //值更改觸發
    grv.CellValueChanged += (s, e) =>
    {
        //根據數量計算金額
        //if (e.Column.FieldName == "Quantity" && e.Value != null)
        //{
        //    var Price = string.Concat(grv.GetFocusedRowCellValue("Price")).ToDecimal();
        //    var Quantity = string.Concat(e.Value).ToDecimal();
        //    grv.SetFocusedRowCellValue("Amount", Price * Quantity);
        //}
    };
    //單元格樣式
    grv.RowCellStyle += (s, e) =>
    {
        //設置特殊顏色標誌
        if (editFields.Contains(e.Column.FieldName))
        {
            e.Appearance.BackColor = Color.Azure;
            e.Appearance.ForeColor = Color.Blue;
        }
    };
}

初始化BandedGridView信息後,如需綁定數據,那麼還需要對GridControl的數據源進行綁定才能進行編輯或者顯示,如下所示的代碼操作。

/// <summary>
/// 綁定數據列表
/// </summary>
private void BindData()
{
    var table = DataTableHelper.CreateTable("Id|int,姓名,外科皮膚科_診斷,外科皮膚科_結論,神經精神科_診斷,神經精神科_結論,內科_診斷,內科_結論,眼科_診斷,眼科_結論,檢查時間,備註");
    
    //準備飛行員體檢測試數據
    for (int i =1; i <= 50;i++)
    {
        var dr = table.NewRow();
        dr["Id"] = i;
        dr["姓名"] = $"某某{i}";

        dr["外科皮膚科_診斷"] = "健康";
        dr["外科皮膚科_結論"] = "合格";

        dr["神經精神科_診斷"] = "健康";
        dr["神經精神科_結論"] = "合格";

        dr["內科_診斷"] = "健康";
        dr["內科_結論"] = "合格";

        dr["眼科_診斷"] = "健康";
        dr["眼科_結論"] = "合格";

        dr["檢查時間"] = DateTime.Now;
        dr["備註"] = "";

        table.Rows.Add(dr);
    }

    //綁定數據源
    var grv = this.bandedGridView1;
    grv.GridControl.DataSource = table;
    grv.RefreshData();
}

最後,我們把它放在開發框架(如有Winform界面部分的SqlSugar開發框架、Winform開發框架)的綜合演示案例裡面,供參考使用。界面效果如下所示。

對比手工的效果

實現功能差不多,通過代碼方式,相對更加靈活一些。

以上就是綜合介紹了手工處理和代碼處理兩種方式構建多行表頭的處理操作,通過使用擴展函數方式,可以更快捷、更靈活的創建多表頭的處理和數據的綁定展示,可以有效的減少我們在多表頭上的操作摸索時間。

 

專註於代碼生成工具、.Net/.NetCore 框架架構及軟體開發,以及各種Vue.js的前端技術應用。著有Winform開發框架/混合式開發框架、微信開發框架、Bootstrap開發框架、ABP開發框架、SqlSugar開發框架等框架產品。
  轉載請註明出處:撰寫人:伍華聰  http://www.iqidi.com 
    

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ## **前言** 在基於Mybatis的開發模式中,很多開發者還會選擇Mybatis-Plus來輔助功能開發,以此提高開發的效率。雖然Mybatis也有代碼生成的工具,但Mybatis-Plus由於在Mybatis基礎上做了一些調整,因此,常規的生成工具生成的代碼還有一些不太符合預期。而且對於多數 ...
  • 在 Django 中,你可以使用 datetime 模塊來計算兩個 TimeField 欄位的時間差。以下是一個示例: from datetime import datetime, timedelta # 假設有兩個 TimeField 欄位 time1 = obj.time_field1 time ...
  • ## HashSet 1. jdk1.7之前,使用數組加鏈表的方式實現 2. jdk1.8之後,在鏈表長度大於8並且數組長度超過32的情況下,會轉成紅黑樹結構 3. HashSet的本質是一個HashMap,它所有的value都是一致的,傳入的參數作為key,因此HashSet中不允許重覆數據 4. ...
  • 聖天諾LDK加密鎖(加密狗),對war包加密的測試,測試war包(或jar包)防止被反編譯的效果。 http://chinadlp.com/?list-DriveDownload.html 下載最新開發套件:Sentinel HASP/LDK9.0開發套件。完全預設安裝。 如果是有主鎖的正式用戶請導 ...
  • ## 前言 對接某公司的介面,涉及到資質上傳等業務。需要對接他們的上傳附件介面。 JDK1.8 httpclient 4.x ## 封裝httpclient方法 ```java public static String postFileMultiPart(String url,Map reqPara ...
  • **本文將為大家詳細講解Java中的,這是我們進行開發時經常用到的知識點,也是大家在學習Java中很重要的一個知識點,更是我們在面試時有可能會問到的問題。** **文章較長,乾貨滿滿,建議大家收藏慢慢學習。文末有本文重點總結,主頁有全系列文章分享。技術類問題,歡迎大家和我們一起交流討論!** ### ...
  • ## 一:背景 ### 1. 講故事 上周有位朋友在 github 上向我求助,說線程都被卡住了,讓我幫忙看下,截圖如下: ![](https://img2023.cnblogs.com/blog/214741/202305/214741-20230522152950051-1097264208.p ...
  • 在.NET開發過程中,可以使用一些輔助的代碼生成器來提高開發效率,之前在.NET FW時代有國產的“動軟代碼生成器”,現在早已不維護了。下麵介紹幾種.NET碼生成器,供大家參考使用。最後一個代碼生產器絕對優秀,推薦使用。 **T4 Text Template Generator:** 簡介:T4是. ...
一周排行
    -Advertisement-
    Play Games
  • 最近做項目過程中,使用到了海康相機,官方只提供了C/C++的SDK,沒有搜尋到一個合適的封裝了的C#庫,故自己動手,簡單的封裝了一下,方便大家也方便自己使用和二次開發 ...
  • 前言 MediatR 是 .NET 下的一個實現消息傳遞的庫,輕量級、簡潔高效,用於實現進程內的消息傳遞機制。它基於中介者設計模式,支持請求/響應、命令、查詢、通知和事件等多種消息傳遞模式。通過泛型支持,MediatR 可以智能地調度不同類型的消息,非常適合用於領域事件處理。 在本文中,將通過一個簡 ...
  • 前言 今天給大家推薦一個超實用的開源項目《.NET 7 + Vue 許可權管理系統 小白快速上手》,DncZeus的願景就是做一個.NET 領域小白也能上手的簡易、通用的後臺許可權管理模板系統基礎框架。 不管你是技術小白還是技術大佬或者是不懂前端Vue 的新手,這個項目可以快速上手讓我們從0到1,搭建自 ...
  • 第1章:WPF概述 本章目標 瞭解Windows圖形演化 瞭解WPF高級API 瞭解解析度無關性概念 瞭解WPF體繫結構 瞭解WPF 4.5 WPF概述 ​ 歡迎使用 Windows Presentation Foundation (WPF) 桌面指南,這是一個與解析度無關的 UI 框架,使用基於矢 ...
  • 在日常開發中,並不是所有的功能都是用戶可見的,還在一些背後默默支持的程式,這些程式通常以服務的形式出現,統稱為輔助角色服務。今天以一個簡單的小例子,簡述基於.NET開發輔助角色服務的相關內容,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 第3章:佈局 本章目標 理解佈局的原則 理解佈局的過程 理解佈局的容器 掌握各類佈局容器的運用 理解 WPF 中的佈局 WPF 佈局原則 ​ WPF 視窗只能包含單個元素。為在WPF 視窗中放置多個元素並創建更貼近實用的用戶男面,需要在視窗上放置一個容器,然後在這個容器中添加其他元素。造成這一限制的 ...
  • 前言 在平時項目開發中,定時任務調度是一項重要的功能,廣泛應用於後臺作業、計劃任務和自動化腳本等模塊。 FreeScheduler 是一款輕量級且功能強大的定時任務調度庫,它支持臨時的延時任務和重覆迴圈任務(可持久化),能夠按秒、每天/每周/每月固定時間或自定義間隔執行(CRON 表達式)。 此外 ...
  • 目錄Blazor 組件基礎路由導航參數組件參數路由參數生命周期事件狀態更改組件事件 Blazor 組件 基礎 新建一個項目命名為 MyComponents ,項目模板的交互類型選 Auto ,其它保持預設選項: 客戶端組件 (Auto/WebAssembly): 最終解決方案裡面會有兩個項目:伺服器 ...
  • 先看一下效果吧: isChecked = false 的時候的效果 isChecked = true 的時候的效果 然後我們來實現一下這個效果吧 第一步:創建一個空的wpf項目; 第二步:在項目裡面添加一個checkbox <Grid> <CheckBox HorizontalAlignment=" ...
  • 在編寫上位機軟體時,需要經常處理命令拼接與其他設備進行通信,通常對不同的命令封裝成不同的方法,擴展稍許麻煩。 本次擬以特性方式實現,以兼顧維護性與擴展性。 思想: 一種命令對應一個類,其類中的各個屬性對應各個命令段,通過特性的方式,實現其在這包數據命令中的位置、大端或小端及其轉換為對應的目標類型; ...