// *********************************************************************** // Assembly : JinYuan.ControlLib // Created : 08-09-2019 // // *********************************************************************** // // Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com // // // Blog: https://www.cnblogs.com/bfyx // GitHub:https://github.com/kwwwvagaa/NetWinformControl // gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git // // If you use this code, please keep this note. // *********************************************************************** using JinYuan.ControlLib.UCHelper; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Windows.Forms; namespace JinYuan.ControlLib { /// /// Class UCDataGridView. /// Implements the /// /// public partial class UCDataGridView : UserControl { #region 属性 /// /// The m head pading left /// private int m_headPadingLeft = 0; /// /// Gets or sets the head pading left. /// /// The head pading left. [Description("标题左侧间距"), Category("自定义")] public int HeadPadingLeft { get { return m_headPadingLeft; } set { m_headPadingLeft = value; this.panHeadLeft.Width = m_headPadingLeft; } } /// /// The m head font /// private Font m_headFont = new Font("微软雅黑", 12F); /// /// 标题字体 /// /// The head font. [Description("标题字体"), Category("自定义")] public Font HeadFont { get { return m_headFont; } set { m_headFont = value; } } /// /// The m head text color /// private Color m_headTextColor = Color.Black; /// /// 标题字体颜色 /// /// The color of the head text. [Description("标题文字颜色"), Category("自定义")] public Color HeadTextColor { get { return m_headTextColor; } set { m_headTextColor = value; } } /// /// The m is show head /// private bool m_isShowHead = true; /// /// 是否显示标题 /// /// true if this instance is show head; otherwise, false. [Description("是否显示标题"), Category("自定义")] public bool IsShowHead { get { return m_isShowHead; } set { if (m_isShowHead != value) { m_isShowHead = value; panHead.Visible = value; if (value) { this.panRow.Location = new Point(0, panHead.Height); this.panRow.Height = this.panRow.Height - panHead.Height; } else { this.panRow.Location = new Point(0, 0); this.panRow.Height = this.panRow.Height + panHead.Height; } } } } /// /// The m head height /// private int m_headHeight = 40; /// /// 标题高度 /// /// The height of the head. [Description("标题高度"), Category("自定义")] public int HeadHeight { get { return m_headHeight; } set { m_headHeight = value; panHead.Height = value; this.Padding = new Padding(0, value, 0, 0); } } /// /// The m is show CheckBox /// private bool m_isShowCheckBox = false; /// /// 是否显示复选框 /// /// true if this instance is show CheckBox; otherwise, false. [Description("是否显示选择框"), Category("自定义")] public bool IsShowCheckBox { get { return m_isShowCheckBox; } set { if (value != m_isShowCheckBox) { m_isShowCheckBox = value; LoadColumns(); } } } /// /// The m row height /// private int m_rowHeight = 40; /// /// 行高 /// /// The height of the row. [Description("数据行高"), Category("自定义")] public int RowHeight { get { return m_rowHeight; } set { m_rowHeight = value; } } /// /// Gets the show count. /// /// The show count. [Description("当前高度可显示行个数"), Category("自定义")] public int ShowCount { get { return this.panRow.Height / (m_rowHeight); } } /// /// The m columns /// private List m_columns = null; /// /// 列 /// /// The columns. [Description("列"), Category("自定义")] public List Columns { get { return m_columns; } set { m_columns = value; LoadColumns(); } } /// /// The m data source /// private object m_dataSource = null; /// /// 数据源,支持列表或table,如果使用翻页控件,请使用翻页控件的DataSource /// /// The data source. /// 数据源不是有效的数据类型,请使用Datatable或列表 /// 数据源不是有效的数据类型,请使用Datatable或列表 [Description("数据源,支持列表或table,如果使用翻页控件,请使用翻页控件的DataSource"), Category("自定义")] public object DataSource { get { return m_dataSource; } set { if (value != null) { if (!(value is DataTable) && (!typeof(IList).IsAssignableFrom(value.GetType()))) { throw new Exception("数据源不是有效的数据类型,请使用Datatable或列表"); } } m_dataSource = value; if (m_columns != null && m_columns.Count > 0) { ReloadSource(); } if (BindingSourceEvent != null) { BindingSourceEvent(this, null); } } } /// /// Gets the rows. /// /// The rows. public List Rows { get; private set; } /// /// The m row type /// private Type m_rowType = typeof(UCDataGridViewRow); /// /// 行元素类型,默认UCDataGridViewItem /// /// The type of the row. /// 行控件没有实现IDataGridViewRow接口 /// 行控件没有实现IDataGridViewRow接口 [Description("行控件类型,默认UCDataGridViewRow,如果不满足请自定义行控件实现接口IDataGridViewRow"), Category("自定义")] public Type RowType { get { return m_rowType; } set { if (value == null) return; if (!typeof(IDataGridViewRow).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control))) throw new Exception("行控件没有实现IDataGridViewRow接口"); m_rowType = value; if (m_columns != null && m_columns.Count > 0) ReloadSource(); } } /// /// The m select row /// IDataGridViewRow m_selectRow = null; /// /// 选中的节点 /// /// The select row. [Description("选中行"), Category("自定义")] public IDataGridViewRow SelectRow { get { return m_selectRow; } private set { m_selectRow = value; } } /// /// 选中的行,如果显示CheckBox,则以CheckBox选中为准 /// /// The select rows. [Description("选中的行,如果显示CheckBox,则以CheckBox选中为准"), Category("自定义")] public List SelectRows { get { return GetSelectRows(); } } /// /// Gets the select rows. /// /// List<IDataGridViewRow>. private List GetSelectRows() { List lst = new List(); if (m_isShowCheckBox) { if (Rows != null && Rows.Count > 0) lst.AddRange(Rows.FindAll(p => p.IsChecked)); } else { if (m_selectRow != null) lst.AddRange(new List() { m_selectRow }); } if (Rows != null && Rows.Count > 0 && m_rowType == typeof(UCDataGridViewTreeRow)) { foreach (UCDataGridViewTreeRow row in Rows) { lst.AddRange(FindTreeRowSelected(row)); } } return lst; } private List FindTreeRowSelected(UCDataGridViewTreeRow row) { List lst = new List(); var _lst = row.ChildrenRows.FindAll(p => p.IsChecked); lst.AddRange(_lst); foreach (UCDataGridViewTreeRow _row in row.ChildrenRows) { lst.AddRange(FindTreeRowSelected(_row)); } return lst; } /// /// Finds the child grid. /// /// The c. /// UCDataGridView. private UCDataGridView FindChildGrid(Control c) { foreach (Control item in c.Controls) { if (item is UCDataGridView) return item as UCDataGridView; else if (item.Controls.Count > 0) { var grid = FindChildGrid(item); if (grid != null) return grid; } } return null; } [Bindable(false)] [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [EditorBrowsable(EditorBrowsableState.Never)] public override bool AutoScroll { get { return base.AutoScroll; } set { base.AutoScroll = value; } } #region 事件 /// /// The head CheckBox change event /// [Description("选中标题选择框事件"), Category("自定义")] public EventHandler HeadCheckBoxChangeEvent; /// /// The head column click event /// [Description("标题点击事件"), Category("自定义")] public EventHandler HeadColumnClickEvent; /// /// Occurs when [item click]. /// [Description("项点击事件"), Category("自定义")] public event DataGridViewEventHandler ItemClick; /// /// Occurs when [source changed]. /// [Description("行数据源改变事件"), Category("自定义")] public event DataGridViewEventHandler RowSourceChangedEvent; /// /// Occurs when [row custom event]. /// [Description("预留的自定义的事件,比如你需要在行上放置删改等按钮时,可以通过此事件传递出来"), Category("自定义")] public event DataGridViewRowCustomEventHandler RowCustomEvent; [Description("绑定数据源后事件"), Category("自定义")] public event EventHandler BindingSourceEvent; #endregion #endregion /// /// Initializes a new instance of the class. /// public UCDataGridView() { InitializeComponent(); } #region 私有方法 #region 加载column /// /// 功能描述:加载column /// 作  者:HZH /// 创建日期:2019-08-08 17:51:50 /// 任务编号:POS /// private void LoadColumns() { try { if (DesignMode) { return; } ControlHelper.FreezeControl(this.panHead, true); this.panRow.Controls.Clear(); this.panColumns.Controls.Clear(); this.panColumns.ColumnStyles.Clear(); if (m_columns != null && m_columns.Count() > 0) { int _width = 0; m_columns.ForEach(p => { if (p.WidthType == SizeType.Absolute) { _width += p.Width; } else if (p.WidthType == SizeType.Percent) { _width += (int)((p.Width / 100f) * this.Width); } }); if (m_isShowCheckBox) _width += 30; if (_width > this.Width) { //this.panRow.Width = _width; this.panHead.Width = _width; } else { if (m_columns.Any(p => p.WidthType == SizeType.AutoSize)) { //this.panRow.Width = this.Width; this.panHead.Width = this.Width; } else { //this.panRow.Width = _width; this.panHead.Width = _width; } } m_columns.FindAll(p => p.WidthType == SizeType.Absolute); m_columns.FindAll(p => p.WidthType == SizeType.Percent); int intColumnsCount = m_columns.Count(); if (m_isShowCheckBox) { intColumnsCount++; } this.panColumns.ColumnCount = intColumnsCount; for (int i = 0; i < intColumnsCount; i++) { Control c = null; if (i == 0 && m_isShowCheckBox) { this.panColumns.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(SizeType.Absolute, 30F)); UCCheckBox box = new UCCheckBox(); box.TextValue = ""; box.Size = new Size(30, 30); box.CheckedChangeEvent += (a, b) => { Rows.ForEach(p => p.IsChecked = box.Checked); if (HeadCheckBoxChangeEvent != null) { HeadCheckBoxChangeEvent(a, b); } }; c = box; } else { var item = m_columns[i - (m_isShowCheckBox ? 1 : 0)]; this.panColumns.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(item.WidthType, item.Width)); Label lbl = new Label(); lbl.Name = "dgvColumns_" + i; lbl.Text = item.HeadText; lbl.Font = m_headFont; lbl.ForeColor = m_headTextColor; lbl.TextAlign = ContentAlignment.MiddleCenter; lbl.AutoSize = false; lbl.Dock = DockStyle.Fill; lbl.MouseDown += (a, b) => { if (HeadColumnClickEvent != null) { HeadColumnClickEvent(a, b); } }; c = lbl; } this.panColumns.Controls.Add(c, i, 0); } } } finally { ControlHelper.FreezeControl(this.panHead, false); } } #endregion #endregion #region 公共函数 /// /// 刷新数据 /// public void ReloadSource() { if (DesignMode) { return; } try { ControlHelper.FreezeControl(this, true); panHead.Location = new Point(0, 0); Rows = new List(); if (m_columns == null || m_columns.Count <= 0) return; if (m_dataSource != null) { int intIndex = 0; int intSourceCount = 0; if (m_dataSource is DataTable) { intSourceCount = (m_dataSource as DataTable).Rows.Count; } else if (typeof(IList).IsAssignableFrom(m_dataSource.GetType())) { intSourceCount = (m_dataSource as IList).Count; } foreach (Control item in this.panRow.Controls) { if (intIndex >= intSourceCount) { item.Visible = false; } else { var row = (item as IDataGridViewRow); row.IsShowCheckBox = m_isShowCheckBox; if (m_dataSource is DataTable) { row.DataSource = (m_dataSource as DataTable).Rows[intIndex]; } else { row.DataSource = (m_dataSource as IList)[intIndex]; } row.BindingCellData(); if (row.RowHeight != m_rowHeight) row.RowHeight = m_rowHeight; item.Visible = true; item.Width = panHead.Width; Rows.Add(row); row.RowIndex = Rows.IndexOf(row); } intIndex++; } if (intIndex < intSourceCount) { for (int i = intIndex; i < intSourceCount; i++) { IDataGridViewRow row = (IDataGridViewRow)Activator.CreateInstance(m_rowType); if (m_dataSource is DataTable) { row.DataSource = (m_dataSource as DataTable).Rows[i]; } else { row.DataSource = (m_dataSource as IList)[i]; } row.Columns = m_columns; List lstCells = new List(); row.IsShowCheckBox = m_isShowCheckBox; row.ReloadCells(); row.BindingCellData(); Control rowControl = (row as Control); rowControl.Width = panHead.Width; row.RowHeight = m_rowHeight; row.CellClick += (a, b) => { this.FindForm().ActiveControl = this; rowControl.Focus(); SetSelectRow(rowControl, b); }; row.CheckBoxChangeEvent += (a, b) => { SetSelectRow(rowControl, b); }; row.RowCustomEvent += (a, b) => { if (RowCustomEvent != null) { RowCustomEvent(a, b); } }; row.SourceChanged += RowSourceChanged; Rows.Add(row); row.RowIndex = Rows.IndexOf(row); this.panRow.Controls.Add(rowControl); } } //this.panRow.Height = intSourceCount * RowHeight; } else { foreach (Control item in this.panRow.Controls) { item.Visible = false; } } } finally { ControlHelper.FreezeControl(this, false); } } /// /// 快捷键 /// /// 通过引用传递的 ,它表示要处理的窗口消息。 /// 值之一,它表示要处理的键。 /// 如果字符已由控件处理,则为 true;否则为 false。 protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { if (keyData == Keys.Up) { Previous(); } else if (keyData == Keys.Down) { Next(); } else if (keyData == Keys.Home) { First(); } else if (keyData == Keys.End) { End(); } return base.ProcessCmdKey(ref msg, keyData); } /// /// 选中第一个 /// public void First() { if (Rows == null || Rows.Count <= 0) return; Control c = null; c = (Rows[0] as Control); SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = 0 }); } /// /// 选中上一个 /// public void Previous() { if (Rows == null || Rows.Count <= 0) return; Control c = null; int index = Rows.IndexOf(m_selectRow); if (index - 1 >= 0) { c = (Rows[index - 1] as Control); SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = index - 1 }); } } /// /// 选中下一个 /// public void Next() { if (Rows == null || Rows.Count <= 0) return; Control c = null; int index = Rows.IndexOf(m_selectRow); if (index + 1 < Rows.Count) { c = (Rows[index + 1] as Control); SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = index + 1 }); } } /// /// 选中最后一个 /// public void End() { if (Rows == null || Rows.Count <= 0) return; Control c = null; c = (Rows[Rows.Count - 1] as Control); SetSelectRow(c, new DataGridViewEventArgs() { RowIndex = Rows.Count - 1 }); } #endregion #region 事件 /// /// Rows the source changed. /// /// The sender. /// The instance containing the event data. void RowSourceChanged(object sender, DataGridViewEventArgs e) { if (RowSourceChangedEvent != null) RowSourceChangedEvent(sender, e); } /// /// Sets the select row. /// /// The item. /// The instance containing the event data. private void SetSelectRow(Control item, DataGridViewEventArgs e) { try { ControlHelper.FreezeControl(this, true); if (item == null) return; if (item.Visible == false) return; this.FindForm().ActiveControl = this; this.FindForm().ActiveControl = item; if (m_selectRow != item) { if (m_selectRow != null) { m_selectRow.SetSelect(false); } m_selectRow = item as IDataGridViewRow; m_selectRow.SetSelect(true); if (this.panRow.Controls.Count > 0) { if (item.Location.Y < 0) { this.panRow.AutoScrollPosition = new Point(0, Math.Abs(this.panRow.Controls[this.panRow.Controls.Count - 1].Location.Y) + item.Location.Y); } else if (item.Location.Y + m_rowHeight > this.panRow.Height) { this.panRow.AutoScrollPosition = new Point(0, Math.Abs(this.panRow.AutoScrollPosition.Y) + item.Location.Y - this.panRow.Height + m_rowHeight); } } } if (ItemClick != null) { ItemClick(item, e); } } finally { ControlHelper.FreezeControl(this, false); } } #endregion private void UCDataGridView_SizeChanged(object sender, EventArgs e) { //LoadColumns(); //ReloadSource(); } private void UCDataGridView_Scroll(object sender, ScrollEventArgs e) { //if (e.ScrollOrientation == ScrollOrientation.VerticalScroll) //{ // panHead.Location = new Point(0, this.VerticalScroll.Value + this.panRow.Location.Y - panHead.Height - 2); //} } private void panRow_Scroll(object sender, ScrollEventArgs e) { if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll && this.panRow.Controls.Count > 0) { Console.WriteLine(this.panRow.HorizontalScroll.Value); Console.WriteLine(this.panRow.Controls[0].Location.X); panHead.Location = new Point(this.panRow.HorizontalScroll.Value * -1, 0); } } } }