最近cs项目中有个看板的功能需求,整个系统是基于DevExpress组件开发的,由于对这个组件的布局不是很熟,也借鉴了网上一些其他人的做法,普遍都是通过GridControl的BandedGridView来实现的,但是网上很多做法都是从设计视图手动创建绑定Brand的,并不是动态生成的,于是我花了半天时间,把这个控件的用法研究了一下,可以通过代码动态创建生成表头,写了个demo,在这和大家分享一下。
GridControl里面默认的控件是GridView,需要手动转换成BrandedGridView,具体如何转换,网上有很多,这里就不详细介绍了。
先看下designer的代码:
namespace WindowsFormsApplication1 { partial class Form2 { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.panel1 = new System.Windows.Forms.Panel(); this.button1 = new System.Windows.Forms.Button(); this.gridControl1 = new DevExpress.XtraGrid.GridControl(); this.bandedGridView1 = new DevExpress.XtraGrid.Views.BandedGrid.BandedGridView(); this.panel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridControl1)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.bandedGridView1)).BeginInit(); this.SuspendLayout(); // // panel1 // this.panel1.Controls.Add(this.button1); this.panel1.Dock = System.Windows.Forms.DockStyle.Top; this.panel1.Location = new System.Drawing.Point(0, 0); this.panel1.Name = "panel1"; this.panel1.Size = new System.Drawing.Size(600, 49); this.panel1.TabIndex = 0; // // button1 // this.button1.Location = new System.Drawing.Point(21, 12); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(75, 23); this.button1.TabIndex = 0; this.button1.Text = "演示"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // // gridControl1 // this.gridControl1.Dock = System.Windows.Forms.DockStyle.Fill; this.gridControl1.Location = new System.Drawing.Point(0, 49); this.gridControl1.MainView = this.bandedGridView1; this.gridControl1.Name = "gridControl1"; this.gridControl1.Size = new System.Drawing.Size(600, 361); this.gridControl1.TabIndex = 1; this.gridControl1.ViewCollection.AddRange(new DevExpress.XtraGrid.Views.Base.BaseView[] { this.bandedGridView1}); // // bandedGridView1 // this.bandedGridView1.GridControl = this.gridControl1; this.bandedGridView1.Name = "bandedGridView1"; this.bandedGridView1.OptionsView.ShowGroupPanel = false; this.bandedGridView1.OptionsView.ShowIndicator = false; this.bandedGridView1.CustomDrawCell += BandedGridView1_CustomDrawCell; // // Form2 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(600, 410); this.Controls.Add(this.gridControl1); this.Controls.Add(this.panel1); this.Name = "Form2"; this.Text = "Form2"; this.panel1.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.gridControl1)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.bandedGridView1)).EndInit(); this.ResumeLayout(false); } #endregion private System.Windows.Forms.Panel panel1; private System.Windows.Forms.Button button1; private DevExpress.XtraGrid.GridControl gridControl1; private DevExpress.XtraGrid.Views.BandedGrid.BandedGridView bandedGridView1; } }
然后是界面的代码:
using System; using System.Collections.Generic; using System.Data; using System.Drawing; using System.Windows.Forms; using DevExpress.Utils; using DevExpress.XtraGrid.Views.BandedGrid; using DevExpress.XtraGrid.Views.Base; namespace WindowsFormsApplication1 { public partial class Form2 : Form { public Form2() { InitializeComponent(); InitBandGrid(); } private void button1_Click(object sender, EventArgs e) { gridControl1.DataSource = GetData(); } List<ColumnHeaderInfo> InitColumnHeader() { string[] Day = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" }; List<ColumnHeaderInfo> list = new List<ColumnHeaderInfo>(); var date = DateTime.Now.Date; for (int i = 0; i < 7; i++) { var colDate = date.AddDays(i); ColumnHeaderInfo info = new ColumnHeaderInfo { Date = colDate.ToString("yyyy-MM-dd"), WeekDay = Day[Convert.ToInt32(colDate.DayOfWeek.ToString("d"))] }; list.Add(info); } return list; } /// <summary> /// 根据仓库权限初始化仓库显示列头 /// </summary> private void InitBandGrid() { var list = InitColumnHeader(); bandedGridView1.BeginUpdate(); bandedGridView1.BeginDataUpdate(); bandedGridView1.BandPanelRowHeight = 42; bandedGridView1.RowHeight = 42; bandedGridView1.OptionsView.ShowColumnHeaders = false; //因为有Band列了,所以把ColumnHeader隐藏 bandedGridView1.OptionsView.AllowCellMerge = true; bandedGridView1.Bands.Clear(); GridBand gbStoreType = new GridBand { Name = @"StoreType", Caption = @" " }; BandedGridColumn col = new BandedGridColumn { Name = "colStoreType", Caption = @" ", FieldName = "StoreType", Visible = true }; gbStoreType.Columns.Add(col); //把新增的显示字段绑定到gridband上,以供显示数据用 bandedGridView1.Bands.Add(gbStoreType); gbStoreType.View.Columns.Add(col); if (list != null) foreach (var item in list) { GridBand gbDate = new GridBand { Name = @"Date_" + item.Date, Caption = item.Date }; GridBand gbWeekDay = gbDate.Children.AddBand(item.WeekDay); GridBand gbCol1 = gbWeekDay.Children.AddBand("预约收货时段"); //必须先将其绑定至bandgridview上后才能去添加column,否则无法加载数据 var bandName1 = "Date_WeekDay_col1_" + item.Date; var bandFieldName1 = "Date_WeekDay_col1_" + item.Date; BandedGridColumn col1 = new BandedGridColumn { Name = bandName1, Caption = @"预约收货时段", FieldName = bandFieldName1, Visible = true }; gbCol1.Columns.Add(col1); //把新增的显示字段绑定到gridband上,以供显示数据用 GridBand gbCol2 = gbWeekDay.Children.AddBand("实际预约/最大预约"); var bandName2 = "Date_WeekDay_col2_" + item.Date; var bandFieldName2 = "Date_WeekDay_col2_" + item.Date; BandedGridColumn col2 = new BandedGridColumn { Name = bandName2, Caption = @"实际预约/最大预约", FieldName = bandFieldName2, Visible = true }; gbCol2.Columns.Add(col2); //把新增的显示字段绑定到gridband上,以供显示数据用 bandedGridView1.Bands.Add(gbDate); gbCol1.View.Columns.Add(col1); gbCol2.View.Columns.Add(col2); col1.OptionsColumn.AllowMerge = DefaultBoolean.False; col2.OptionsColumn.AllowMerge = DefaultBoolean.False; gbDate.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center; //这是合并表头居中显示 gbWeekDay.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center; //这是合并表头居中显示 gbCol1.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center; //这是合并表头居中显示 gbCol2.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center; //这是合并表头居中显示 } bandedGridView1.EndDataUpdate(); bandedGridView1.EndUpdate(); } private void BandedGridView1_CustomDrawCell(object sender, RowCellCustomDrawEventArgs e) { var currentView = sender as BandedGridView; if (currentView == null) return; var row = currentView.GetDataRow(e.RowHandle); if (row["RedColumnIndex"] != DBNull.Value && !string.IsNullOrWhiteSpace(e.CellValue.ToString())) { string[] args = row["RedColumnIndex"].ToString() .Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries); foreach (var arg in args) { if (e.Column.VisibleIndex == int.Parse(arg)) { e.Appearance.BackColor = Color.Red; } } } if (row["GreenColumnIndex"] != DBNull.Value && !string.IsNullOrWhiteSpace(e.CellValue.ToString())) { string[] args = row["GreenColumnIndex"].ToString() .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (var arg in args) { if (e.Column.VisibleIndex == int.Parse(arg)) { e.Appearance.BackColor = Color.Green; } } } } DataTable GetData() { var list = InitColumnHeader(); DataTable dt = new DataTable(); dt.Columns.Add("StoreType"); foreach (var item in list) { dt.Columns.Add("Date_WeekDay_col1_" + item.Date); dt.Columns.Add("Date_WeekDay_col2_" + item.Date); } dt.Columns.Add("RedColumnIndex"); dt.Columns.Add("GreenColumnIndex"); dt.Rows.Add("常温","8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800","2,4,6,8,10,12,14",""); dt.Rows.Add("常温","8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "", "6,8,10,12,14"); dt.Rows.Add("常温","8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "10,12,14",""); dt.Rows.Add("冷冻", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800","",""); dt.Rows.Add("冷冻", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800","",""); dt.Rows.Add("冷冻", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800", "8:00-9:00", "1000/800","",""); return dt; } public class ColumnHeaderInfo { public string Date { get; set; } public string WeekDay { get; set; } } } }
运行后的效果:
说明:
- Demo数据仅为了展示,所以我在窗体代码里面写死了,绑定的动态数据源最好是DataTable类型,因为列名也是动态创建生成的,可扩展性比较强
- 为了美观,设置了BrandedGridView的行高属性:BandPanelRowHeight表头高度,RowHeight每行数据单元格的行高
- 需求中有预警设置指定单元格背景色的功能,以前用普通的DataGridViiew的时候,有CellFormating事件,处理比较方便,GridView控件里面有个类似的事件,叫CustomDrawCell,具体实现可参考以上代码
到此为止,基本上就实现了如何用代码动态创建生成复合表头的功能,希望可以对大家有所帮助,谢谢