重写DataGridView实现shift键与DataGridView复选框的结合,类似与资源管理器中的shift按键功能

//重写DataGridView

public class DataGrid:DataGridView
    {
        private Image backgroundImage;
        private ShiftKeyAndGrid _shiftGrid;

        public DataGrid()
        {
            this._shiftGrid = new ShiftKeyAndGrid(this);
            this.KeyDown += new KeyEventHandler(DataGrid_KeyDown);
            this.KeyUp += new KeyEventHandler(DataGrid_KeyUp);
            this.CellClick += new DataGridViewCellEventHandler(DataGrid_CellClick);
        }

        void DataGrid_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            this._shiftGrid.ChangedGrid(sender, e); 
        }

        void DataGrid_KeyUp(object sender, KeyEventArgs e)
        {
            this._shiftGrid.KeyUpGrid(sender, e);
        }

        void DataGrid_KeyDown(object sender, KeyEventArgs e)
        {
            this._shiftGrid.KeyDownGrid(sender, e);
        }

        [Description("设置或获取背景图片")]
        public Image BackGroundImage
        {

            get
            {
                return backgroundImage;
            }
            set
            {
                backgroundImage = value;
                this.Invalidate();
            }

        }

        public List<int> GetSelectedRowIndex(int columnIndex)
        {
            if (this.Columns[0] is DataGridViewCheckBoxColumn)
            {
                List<int> lstId = new List<int>();
                for (int i = 0; i < this.Rows.Count; i++)
                {
                    DataGridViewRow row = this.Rows[i];
                    if ((bool)row.Cells[columnIndex].Value)
                    {
                        lstId.Add(i);
                    }
                }
                return lstId;
            }
            else
            {
                return null;
            }
        }

        protected override void PaintBackground(Graphics graphics, Rectangle clipBounds, Rectangle gridBounds)
        {
            base.PaintBackground(graphics, clipBounds, gridBounds);
            if (backgroundImage != (Image)null)
            {
                graphics.DrawImage(backgroundImage, gridBounds);
            }
        }
    }

用到的附加类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace CustomControls
{
    public delegate void DelChangeGrid(int rowIndex, int columnIndex);

    public class ShiftKeyAndGrid
    {
        bool _isShiftKeyDown;
        int _startCheckBox;
        int _lastEndCheckBox;//面向类内部有效       
        DataGridView _grid;

        /// <summary>
        /// 调用页面有几个grid,就实例化几个该类对象
        /// </summary>
        public ShiftKeyAndGrid(DataGridView grid)
        {
            this._isShiftKeyDown = false;
            this._startCheckBox = -1;
            this._lastEndCheckBox = -1;
            this._grid = grid;
        }

        public ShiftKeyAndGrid(DataGridView grid, int selectedIndex)
            : this(grid)
        {
            this._startCheckBox = selectedIndex;
        }

        public bool IsShiftKeyDown
        {
            get
            {
                return this._isShiftKeyDown;
            }
        }

        public void KeyDownGrid(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ShiftKey)
            {
                this._isShiftKeyDown = true;
            }
        }

        public void KeyUpGrid(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ShiftKey)
            {
                this._isShiftKeyDown = false;
                this._lastEndCheckBox = -1;
            }
        }

        /// <summary>
        /// 数组是要作用的列,只有在这些列上的复选框作用时候才有效
        /// 调用ChangedGrid(sender, e, 1,2,3),只有在1,2,3裂伤有效
        /// 也可以这样调用ChangedGrid(sender, e, new int[]{1,2,3}),与上面等效
        /// 假如不存在ChangedGrid(object sender, CellEventArgs e),而只存在ChangedGrid(object sender, CellEventArgs e, params int[] columnIndex)
        /// 那么如果传ChangedGrid(sender, e),那么默认为第零列,相当于传一个0微的数组ChangedGrid(sender, e, new int[0]),
        /// 但是这时候程序如果判断整型的length属性为0,那么默认为第零列
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <param name="columnIndex">要作用的列</param>
        public void ChangedGrid(object sender, DataGridViewCellEventArgs e, params int[] columnIndex)
        {
            if (this._grid.Columns[e.ColumnIndex] is DataGridViewCheckBoxColumn)
            {
                this._grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = !(bool)this._grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
            }
            bool isChangeGrid = IsChangGrid(sender, e, columnIndex);
            if (!isChangeGrid)
            {
                return;
            }
            if (this._grid.Columns[e.ColumnIndex] is DataGridViewCheckBoxColumn)
            {
                if (this._isShiftKeyDown)
                {
                    if (this._startCheckBox == -1)//从来还没有动过复选框
                    {
                        this._startCheckBox = GetGridLastSelectedIndex(e.ColumnIndex, e.RowIndex);//
                    }
                    if (this._startCheckBox == e.RowIndex)
                    {
                        this._grid[e.ColumnIndex, this._startCheckBox].Value = true;
                    }
                    int endCheckBox = e.RowIndex;
                    bool firstCheckState = (bool)this._grid[e.ColumnIndex, this._startCheckBox].Value;
                    SetGridCheckBox(this._startCheckBox, endCheckBox, e.ColumnIndex, firstCheckState);
                    //保存上一次的endCheckBox索引
                    this._lastEndCheckBox = endCheckBox;
                }
                else//假如是在没有俺shift键的情况下,改变复选框,这是最后一个改变的复选框为开始索引
                {
                    this._startCheckBox = e.RowIndex;
                }
            }
        }

        public void ChangedGrid(object sender, DataGridViewCellEventArgs e, DelChangeGrid oldChangeMethod, params int[] columnIndex)
        {
            bool isChangeGrid = IsChangGrid(sender, e, columnIndex);
            if (!isChangeGrid)
            {
                return;
            }
            if (this._grid.Columns[e.ColumnIndex].CellType == typeof(DataGridViewCheckBoxColumn))
            {
                if (this._isShiftKeyDown)
                {
                    if (this._startCheckBox == -1)//从来还没有动过复选框
                    {
                        this._startCheckBox = GetGridLastSelectedIndex(e.ColumnIndex, e.RowIndex);
                    }
                    if (this._startCheckBox == e.RowIndex)
                    {
                        this._grid[e.ColumnIndex, this._startCheckBox].Value = true;
                    }
                    int endCheckBox = e.RowIndex;
                    bool firstCheckState = (bool)this._grid[e.ColumnIndex, this._startCheckBox].Value;
                    SetGridCheckBox(this._startCheckBox, endCheckBox, e.ColumnIndex, firstCheckState, oldChangeMethod);
                    //保存上一次的endCheckBox索引
                    this._lastEndCheckBox = endCheckBox;
                }
                else//假如是在没有俺shift键的情况下,改变复选框,这是最后一个改变的复选框为开始索引
                {
                    this._startCheckBox = e.RowIndex;
                }
            }
        }

        /// <summary>
        /// 只有按下shift情况下才调用此函数
        /// </summary>
        /// <param name="startCheckBox"></param>
        /// <param name="endCheckBox"></param>
        /// <param name="columnIndex"></param>
        /// <param name="firstCheckState"></param>
        private void SetGridCheckBox(int startCheckBox, int endCheckBox, int columnIndex, bool firstCheckState, params DelChangeGrid[] oldChangeMethod)
        {
            int tempCheckBox = -1;
            //保证开始行索引不能大于结束索引
            if (startCheckBox > endCheckBox)
            {
                tempCheckBox = startCheckBox;
                startCheckBox = endCheckBox;
                endCheckBox = tempCheckBox;
            }
            //清空上同一次按下shift键情况下,反复改变结束索引情况下,这时应该清楚上一次的改变状态,
            //也就是说,只有按下shift键的最后一次有效
            if (this._lastEndCheckBox != -1)
            {
                if (this._startCheckBox <= this._lastEndCheckBox)
                {
                    for (int i = this._startCheckBox + 1; i <= this._lastEndCheckBox; i++)
                    {
                        this._grid[columnIndex, i].Value = false;
                        //-----------
                        if (oldChangeMethod != null && oldChangeMethod.Length > 0)
                        {
                            DelChangeGrid del = oldChangeMethod[0];
                            del(i, columnIndex);
                        }
                        //--------------
                    }
                }
                else
                {
                    for (int i = this._lastEndCheckBox; i < this._startCheckBox; i++)
                    {
                        this._grid[columnIndex, i].Value = false;
                        //-----------
                        if (oldChangeMethod != null && oldChangeMethod.Length > 0)
                        {
                            DelChangeGrid del = oldChangeMethod[0];
                            del(i, columnIndex);
                        }
                        //--------------
                    }
                }

            }
            //更新开始索引至结束索引之间的复选框的状态,起状态与起始复选框的状态一样
            for (int i = startCheckBox; i <= endCheckBox; i++)
            {
                this._grid[columnIndex, i].Value = firstCheckState;
                //-----------
                if (oldChangeMethod != null && oldChangeMethod.Length > 0)
                {
                    DelChangeGrid del = oldChangeMethod[0];
                    del(i, columnIndex);
                }
                //--------------
            }
            this._grid.Invalidate();
        }

        /// <summary>
        /// 只有this._startCheckBox为-1时才调用
        /// 假如grid一开始就有选中的,那么开始索引就是最后一个选中的复选框所在的行索引
        /// 否则,即都没有选中,那么开始索引为当前选中行的索引
        /// </summary>
        /// <param name="checkedColumn"></param>
        /// <param name="currentRowIndex"></param>
        /// <returns></returns>
        private int GetGridLastSelectedIndex(int checkedColumn, int currentRowIndex)
        {
            int lastSelectIndex = currentRowIndex;
            for (int i = this._grid.Rows.Count - 1; i >= 0; i--)
            {
                if ((bool)this._grid[checkedColumn, i].Value && currentRowIndex != i)
                {
                    lastSelectIndex = i;
                    break;
                }
            }
            return lastSelectIndex;
        }

        /// <summary>
        /// 根据传过来的参数判断是不是需要相应grid的事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <param name="columnIndex"></param>
        /// <returns></returns>
        private bool IsChangGrid(object sender, DataGridViewCellEventArgs e, int[] columnIndex)
        {
            //假如不是控件本身响应的改变时间,而是程序员调用则返回
            if (e == null)
            {
                return false;
            }
            else
            {
                //假如没有传要作用的列,或者传的是null,那么就传的是第0列,那么如果当前改变的列不是0列,那么直接返回false
                if (columnIndex == null || columnIndex.Length == 0)
                {
                    if (e.ColumnIndex == 0)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else//否则,也就是有一个或者多个要作用的列,这是如果当前改变的列是其中之一,那么就就返回true,否则false
                {
                    bool isContain = false;
                    foreach (int column in columnIndex)
                    {
                        if (column == e.ColumnIndex)
                        {
                            isContain = true;
                            break;
                        }
                    }
                    return isContain;
                }
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值