//重写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;
}
}
}
}
}