1. ホーム
  2. シーピー

C# DataGridView グループ化できるセルを追加する

2022-03-02 08:58:32

1. DataGridViewExコンポーネントを追加します。

    /// <summary>
    /// Extended DataGridView
    /// </summary>
    public class DataGridViewEx : DataGridView
    {
        bool showRowHeaderNumbers;

        /// <summary>
        //// Whether to show row numbers
        /// </summary>
        [Description("whether to show row numbers"), DefaultValue(true)]
        public bool ShowRowHeaderNumbers
        { get
            get { return showRowHeaderNumbers; }
            set 
            {
                if (showRowHeaderNumbers ! = value)
                    Invalidate();
                showRowHeaderNumbers = value; 
            }
        }

        public DataGridViewEx()
        {
            showRowHeaderNumbers = true;
            RowStateChanged += new DataGridViewRowStateChangedEventHandler(DataGridViewEx_RowStateChanged);
        }

        protected override void OnEditingControlShowing(DataGridViewEditingControlShowingEventArgs e)
        {
            if (CurrentCell ! = CurrentCell.OwningColumn is DataGridViewComboBoxColumnEx)
            {
                OwningColumn as DataGridViewComboBoxColumnEx col = CurrentCell;
                // Modify the style of the ComboBox
                if (col.DropDownStyle ! = ComboBoxStyle.DropDownList)
                DropDownList) {
                    ComboBox combo = e. Control as ComboBox;
                    combo.DropDownStyle = col;
                    combo.Leave += new EventHandler(combo_Leave);
                }
            }
            base.OnEditingControlShowing(e);
        }

        /// <summary>
        //// When focus is off, the newly entered value needs to be added to the combo box's Items list
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void combo_Leave(object sender, EventArgs e)
        {
            ComboBox combo = sender as ComboBox;
            combo.Leave -= new EventHandler(combo_Leave);
            if (CurrentCell ! = null && CurrentCell.OwningColumn is DataGridViewComboBoxColumnEx)
            {
                DataGridViewComboBoxColumnEx col = CurrentCell.OwningColumn as DataGridViewComboBoxColumnEx;
                //be sure to add the newly entered value to the list of values in the combo box
                // otherwise the next step will report an error when assigning a value to the cell (because the value is not in the value list of the combo box)
                Items.Add(combo.Text);
                CurrentCell.Value = combo.Text;
            }
        }
        void DataGridViewEx_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e)
        {
            HeaderCell.Value = string.Format("{0}", e.Row.Index);
            
            HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;  
        }

2. DataGridViewGroupColumn クラスを追加します。

    /// <summary>
    /// Groupable columns (the column must be the first column of the Grid)
    /// </summary>
    public class DataGridViewGroupColumn : DataGridViewTextBoxColumn
    {
        public DataGridViewGroupColumn()
        {
            CellTemplate = new DataGridViewGroupCell();
            ReadOnly = true;
        }

        public override DataGridViewCell CellTemplate
        {
            get
            return
                return base.CellTemplate;
            CellTemplate; }
            set
            {
                if ((value ! = null) && ! (value is DataGridViewGroupCell))
                {
                    throw new InvalidCastException("Need System.Windows.Forms.DataGridViewGroupCell");
                }
                base.CellTemplate = value;
            }

        }
    }

    /

        #region add child node

        /// <summary>
        /// Adding child nodes
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        public int AddChildCell(DataGridViewGroupCell cell)
        {
            return AddChildCellRange(new DataGridViewGroupCell[] { cell });
        }

        public int AddChildCellRange(DataGridViewGroupCell[] cells)
        {
            bool needRedraw = false;
            if (childCells == null)
            {
                //need to draw a plus sign
                childCells = new List<DataGridViewGroupCell>();
                needRedraw = true;
            }
            foreach (DataGridViewGroupCell cell in cells)
            {
                childCells.Add(cell);
                cell.groupLevel = groupLevel + 1;
                cell.parentCell = this;
            }

            if (needRedraw)
                DataGridView.InvalidateCell(this);
            return childCells.Count;
        }

        #endregion

        #region draw nodes

        protected override void Paint(System.Drawing, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            if (!bPaint)
            {
                Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
                return;
            }
            Pen gridPen = new Pen(DataGridView.GridColor);
            Brush bruBK = new SolidBrush(cellStyle.BackColor);
            int width = groupLevel * PLUS_WIDTH;
            Rectangle rectLeft = new Rectangle(cellBounds.Left, cellBounds.Top - 1, width, cellBounds.Height);
            cellBounds.X += width;
            cellBounds.Width -= width;
            Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);

            PaintGroupPlus(graphics, gridPen, bruBK, cellStyle, rectLeft, collapsed);

            gridPen.Dispose();
            gridPen = null;

            Dispose(); gridPen = null; bruBK.Dispose();
            bruBK = null;
        }

        private void PaintGroupPlus(Graphics graphics, Pen gridPen, Brush bruBK, DataGridViewCellStyle cellStyle, Rectangle rectLeft, bool collapsed)
        {
            Pen pen = new Pen(DataGridView.GridColor, 1);
            pen.DashStyle = DashStyle.Dot;
            graphics.FillRectangle(bruBK, rectLeft);
            int left = rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH;
            //draw Left, Top, Right lines
            graphics.DrawLine(gridPen, left, rectLeft.Top, rectLeft.Right, rectLeft.Top);//top
            graphics.DrawLine(gridPen, rectLeft.Right, rectLeft.Bottom, rectLeft;)

            // The leftmost line
            graphics.DrawLine(gridPen, rectLeft.Left, rectLeft.Top, rectLeft.Right, rectLeft.Top);

            // If it's the last node of the level, you need to draw a bottom line to close the whole group
            bool drawBottomLine = false;
            for (int i = 1; i < groupLevel; i++)
            {
                if (!ParentCell.IsLastCell(ParentCell.groupLevel))// the upper level is not the last node
                {
                    graphics.DrawLine(pen, rectLeft.Left + (i - 1) * PLUS_WIDTH + PLUS_WIDTH / 2, rectLeft.Top
                        Top, rectLeft.Left + (i - 1) * PLUS_WIDTH + PLUS_WIDTH / 2

3. エフェクトの実装