ps:目前只能将所在的列 垂直合并 不能合并两(多)个不相同的列
相关参数
属性 | 名称 | 作用 | 描述 |
---|---|---|---|
NeedMergeColumns | 需要合并列 | 将合并的列名写入 | |
MergeColumnsReadOnly | 合并列是否只读 | 默认【否】 | |
MergeConditonDict | 合并列的条件字典 | 默认【Null】 | 示例:new Dictionary<string, List>{{ BillDate, new List { BillCode,BillNumber} },}; 意味发票时间 以发票代码+发票号码 两列 以及 发票时间 作为唯一标识,如果重复即合并当前列 |
NeedColumnCheckBox | 需要选择列(可做全选)? | 默认【true】 | |
ColumnCheckBoxTitle | 选择列的标题内容 | 默认【选择】 | |
ColumnCheckBoxName | 选择列的Name值 | 默认【select_check】 | |
RowCheckBoxDataPropName | 选择列的DataPropName | 默认[D_Selected] | |
ColumnCheckBoxInLast | 选择列的位置是否是最后一列 | 默认[false] | 为false时是第一列展示,如果是true以最后一列展示,如果AutoGenerateColumns为true时,ColumnCheckBoxInLast为true,可能不会在最后一列展示,为false则没有任何影响 |
ShowUploadInfoColumnsDict | 需要展示上传信息的列 | 默认【Null】 | 这个是我需要结合业务做的上传列的标记而已,不一定对你有作用,可以忽略 |
使用示范
//设置合并列
groupByDataGrid1.NeedMergeColumns = new string[] { BillCode.Name, BillNumber.Name, BillDate.Name, BillAmount.Name, Bill_Attach.Name };
//设置合并单元格只读
groupByDataGrid1.MergeColumnsReadOnly = true;
//设置对应的合并列的合并条件 一般是前面是合并列 后面是组合起来的唯一标识
//如这个 { BillNumber.Name, new List<string> { BillCode.Name}},
//意味着 BillNumber+BillCode 唯一 如果重复,会将BillNumber列合并
//如果不写合并条件 该列一旦重复即合并
groupByDataGrid1.MergeConditonDict = new Dictionary<string, List<string>>
{
{ BillNumber.Name, new List<string> { BillCode.Name}},
{ BillDate.Name, new List<string> { BillCode.Name,BillNumber.Name } },
{ BillAmount.Name, new List<string> { BillCode.Name, BillNumber.Name}},
{ Bill_Attach.Name, new List<string> { BillCode.Name, BillNumber.Name}}
};
//groupByDataGrid1.ShowUploadInfoColumns = new string[] { Bill_Attach.Name };
IList<OsZbBillInfo> osZbBillInfos = new List<OsZbBillInfo>(){
//此次数量模拟数据
};
groupByDataGrid1.DataSource = osZbBillInfos;
代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace WinformsUserControl.Controls
{
/// <summary>
/// 绘制单元格垂直合并的DataGridView
/// </summary>
public class GroupByDataGrid : DataGridView
{
private string _columnCheckBoxTitle = "选择";
private string _columnCheckBoxName = "select_check";
private string _columnCheckBoxDataPropName = "D_Selected";
private bool _columnCheckBoxInLast = false;
private bool _needColumnCheckbox = true;
/// <summary>
/// 需要绘制单元格
/// </summary>
//private bool _needPaintCell = true;
/// <summary>
/// 需要合并的列
/// </summary>
[Browsable(true)]
[Description("需要合并的列")]
public string[] NeedMergeColumns { get; set; }
/// <summary>
/// 合并列是否只读
/// </summary
[Browsable(true)]
[Description("合并列是否只读")]
public bool MergeColumnsReadOnly { get; set; }
/// <summary>
/// 需要某几项值相同 前面才合并
/// </summary>
[Browsable(false)]
[Description("需要某几项值相同 前面才合并")]
public Dictionary<string,List<string>> MergeConditonDict { get; set; }
/// <summary>
/// 需要展示上传信息的列 字典
/// </summary>
public Dictionary<string,string> ShowUploadInfoColumnsDict = new Dictionary<string, string> ();
private string[] _showUploadInfoColumns;
/// <summary>
/// 需要展示上传信息的列
/// 在控件中无意义 做个标记而已
/// </summary>
[Browsable(false)]
[Description("需要展示上传信息的列")]
public string[] ShowUploadInfoColumns{ private get => _showUploadInfoColumns; set {
_showUploadInfoColumns = value;
foreach (var item in value)
{
if (!ShowUploadInfoColumnsDict.ContainsKey(item))
{
ShowUploadInfoColumnsDict.Add(item, item);
}
}
}
}
/// <summary>
/// 选择列
/// </summary>
private DataGridViewCheckBoxColumn rowCheckBoxColumn = new DataGridViewCheckBoxColumn()
{
AutoSizeMode = DataGridViewAutoSizeColumnMode.None,
Width = 51,
FalseValue = false,
TrueValue = true
};
/// <summary>
/// 是否需要行选择框
/// </summary>
[Browsable(true)]
[Description("是否需要行选择框")]
public bool NeedColumnCheckBox { get => _needColumnCheckbox; set{
_needColumnCheckbox = value;
int insertIndex = ColumnCheckBoxInLast ? this.Columns.Count - 1 : 0;
rowCheckBoxColumn.DisplayIndex = insertIndex;
rowCheckBoxColumn.Visible = value;
if (!Columns.Contains(rowCheckBoxColumn))
{
rowCheckBoxColumn.Name = ColumnCheckBoxName;
rowCheckBoxColumn.DataPropertyName = RowCheckBoxDataPropName;
rowCheckBoxColumn.HeaderText = ColumnCheckBoxTitle;
this.Columns.Insert(insertIndex, rowCheckBoxColumn);
}
}
}
/// <summary>
/// 选择框(列)标题
/// </summary>
[Browsable(true)]
[Description("行选择框标题")]
public string ColumnCheckBoxTitle { get => _columnCheckBoxTitle; set {
_columnCheckBoxTitle = value;
rowCheckBoxColumn.HeaderText = value;
}
}
/// <summary>
/// 选择框(列)标题
/// </summary>
[Browsable(true)]
[Description("行选择框Name")]
public string ColumnCheckBoxName { get => _columnCheckBoxName; set {
_columnCheckBoxName = value;
rowCheckBoxColumn.Name = value;
}
}
/// <summary>
/// 行选择框数据属性名
/// </summary>
[Browsable(true)]
[Description("行选择框数据属性名")]
public string RowCheckBoxDataPropName { get => _columnCheckBoxDataPropName; set {
_columnCheckBoxDataPropName = value;
rowCheckBoxColumn.DataPropertyName = value;
}
}
/// <summary>
/// 选择框(列)是否位于最后一列,默认是第一列
/// </summary>
[Browsable(true)]
[Description("行选择框是否位于最后一列,默认是第一列")]
public bool ColumnCheckBoxInLast { get => _columnCheckBoxInLast; set {
_columnCheckBoxInLast = value;
int insertIndex = value ? this.Columns.Count - 1 : 0;
rowCheckBoxColumn.DisplayIndex = insertIndex;
}
}
public GroupByDataGrid()
{
#region 默认样式
this.BorderStyle = BorderStyle.Fixed3D;
this.BackgroundColor = Color.FromArgb(243, 244, 247);
this.ColumnHeadersDefaultCellStyle = new DataGridViewCellStyle()
{
ForeColor = SystemColors.WindowText,
SelectionBackColor = SystemColors.Highlight,
SelectionForeColor = SystemColors.HighlightText,
Font = new Font("宋体", 9, FontStyle.Regular, GraphicsUnit.Point, 134, false),
WrapMode = DataGridViewTriState.True,
Alignment = DataGridViewContentAlignment.MiddleCenter
};
this.DefaultCellStyle = new DataGridViewCellStyle()
{
BackColor = SystemColors.Window,
ForeColor = SystemColors.ControlText,
SelectionBackColor = Color.FromArgb(255, 0, 188, 212),
SelectionForeColor = SystemColors.HighlightText,
Font = new Font("宋体", 9, FontStyle.Regular, GraphicsUnit.Point, 134, false),
WrapMode = DataGridViewTriState.False,
Alignment = DataGridViewContentAlignment.MiddleLeft
};
//设置公共的样式
CommonDataGridViewRowStyle();
this.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
this.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing;
this.ColumnHeadersHeight = 30; // 设置表头行高为 30 像素
this.AutoGenerateColumns = false; // 默认不自动创建列
this.AllowUserToAddRows = false; // 默认不允许添加行
this.AllowUserToOrderColumns = true; // 默认允许用户拖动列标头来对列重新排序
#endregion
}
protected override void OnCellFormatting(DataGridViewCellFormattingEventArgs args)
{
// Call home to base
base.OnCellFormatting(args);
// First row always displays
if (args.RowIndex == 0)
{
return;
}
Dictionary<string, string> mergeColDict = NeedMergeColumns?.ToDictionary(x => x, x => x);
if (mergeColDict?.ContainsKey(this.Columns[args.ColumnIndex].Name) == true && IsRepeatedCellValue(args.RowIndex, args.ColumnIndex))
{
args.Value = string.Empty;
Rows[args.RowIndex].Cells[args.ColumnIndex].ReadOnly = MergeColumnsReadOnly;
Rows[args.RowIndex-1].Cells[args.ColumnIndex].ReadOnly = MergeColumnsReadOnly;//上一行同样设置只读性
if(Rows[args.RowIndex].Cells[args.ColumnIndex] is DataGridViewButtonCell btnCell)
{
btnCell.Style.NullValue = null; // 隐藏按钮单元格内容
btnCell.Style.BackColor = this.DefaultCellStyle.BackColor; // 隐藏按钮单元格背景色
btnCell.Style.SelectionBackColor = this.DefaultCellStyle.SelectionBackColor; // 隐藏按钮单元格选中背景色
}
Rows[args.RowIndex].Cells[args.ColumnIndex].Tag = "hidden";//标记为隐藏
args.FormattingApplied = true;
}
}
private bool IsRepeatedCellValue(int rowIndex, int colIndex)
{
DataGridViewCell currCell = Rows[rowIndex].Cells[colIndex];
DataGridViewCell prevCell = Rows[rowIndex - 1].Cells[colIndex];
string columnName = this.Columns[colIndex].Name;
bool isMerge = true;
if (MergeConditonDict?.TryGetValue(columnName, out var mapList)==true)
{
foreach (var item in mapList)
{
//如果有跟随合并行 重复 当前列合并 否则不合并
if (!IsRepeatedCellValue(rowIndex, Rows[rowIndex].Cells[item].ColumnIndex))
{
isMerge = false;
}
}
}
if (EqualityComparer<object>.Default.Equals(currCell.Value, prevCell.Value) && isMerge)
{
return true;
}
else
{
return false;
}
}
protected override void OnCellPainting(DataGridViewCellPaintingEventArgs args)
{
base.OnCellPainting(args);
args.AdvancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.None;
Dictionary<string, string> mergeColDict = NeedMergeColumns?.ToDictionary(x => x, x => x);
// Ignore column and row headers and first row
if (args.RowIndex < 1 || args.ColumnIndex < 0)
{
return;
}
//匹配要合并的列
if (mergeColDict?.ContainsKey(this.Columns[args.ColumnIndex].Name) == true && IsRepeatedCellValue(args.RowIndex, args.ColumnIndex))
{
args.AdvancedBorderStyle.Top = DataGridViewAdvancedCellBorderStyle.None;
//当前按钮单元格不绘制
if (Rows[args.RowIndex].Cells[args.ColumnIndex] is DataGridViewButtonCell btnCell)
{
// 取消绘制边框
args.AdvancedBorderStyle.All = DataGridViewAdvancedCellBorderStyle.None;
// 取消绘制内容
args.PaintBackground(args.CellBounds, false);
args.Handled = true;
}
}
else
{
args.AdvancedBorderStyle.Top = AdvancedCellBorderStyle.Top;
}
}
/// <summary>
/// 单元格内容点击
/// </summary>
/// <param name="e"></param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
protected override void OnCellContentClick(DataGridViewCellEventArgs e)
{
base.OnCellContentClick(e);
if (e.RowIndex < 0 || e.ColumnIndex < 0)
{
return;
}
if (Columns[e.ColumnIndex].Name == ColumnCheckBoxName && Rows[e.RowIndex].Cells[e.ColumnIndex].Value is bool bvalue)
{
Rows[e.RowIndex].Cells[e.ColumnIndex].Value = !bvalue;
}
}
/// <summary>
/// 全选和反选
/// </summary>
/// <param name="e"></param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public virtual void RevertChooseAll()
{
foreach (DataGridViewRow row in Rows)
{
if (row.Cells[ColumnCheckBoxName].Value is bool bvalue)
{
row.Cells[ColumnCheckBoxName].Value = !bvalue;
}
}
}
/// <summary>
/// 公共的Datagridview样式
/// </summary>
/// <param name="dataGridView">需要操作的Datagridview</param>
/// <param name="buttonStyle">是否需要操作行里面按钮样式</param>
public void CommonDataGridViewRowStyle(float head_fontSize = 10.5f,float content_fontSize = 11.2f,bool buttonStyle = true)
{
this.RowsDefaultCellStyle.ForeColor = Color.Black;
this.RowsDefaultCellStyle.BackColor = Color.White;
this.RowTemplate.DefaultCellStyle.SelectionBackColor = Color.FromArgb(215, 233, 246);
this.RowTemplate.DefaultCellStyle.SelectionForeColor = Color.Black;
if (buttonStyle)
{
DataGridViewColumnCollection columns = this.Columns;
DataGridViewButtonColumn btnColumn;
foreach (DataGridViewColumn item in columns)
{
//仅操作DataGridViewButtonColumn
if ((btnColumn = item as DataGridViewButtonColumn) != null)
{
btnColumn.CellTemplate.Style.BackColor = Color.FromArgb(243, 244, 247);
btnColumn.FlatStyle = FlatStyle.Popup;
}
}
}
}
/// <summary>
/// 单元格内容改变
/// </summary>
/// <param name="e"></param>
protected override void OnCellValueChanged(DataGridViewCellEventArgs e)
{
base.OnCellValueChanged(e);
if(e.RowIndex < 0 || e.ColumnIndex < 0)
{
return;
}
// 获取改变值的单元格所在的行
DataGridViewRow row = Rows[e.RowIndex];
// 标记该行的所有单元格为无效
InvalidateCell(row.Cells[e.ColumnIndex]);
/*foreach (DataGridViewCell cell in row.Cells)
{
cell.DataGridView.InvalidateCell(cell);
}*/
}
/// <summary>
/// 加载完毕
/// </summary>
/// <param name="e"></param>
protected override void OnDataBindingComplete(DataGridViewBindingCompleteEventArgs e)
{
base.OnDataBindingComplete(e);
//单项内容改变 不重绘
//_needPaintCell = e.ListChangedType != ListChangedType.ItemChanged;
}
}
}