最近,由于做的成绩系统中,需要一列点击按键直接转换成相应的值的列,DataGridView本身无法提供此功能,为此学习了自定义列的知识,在网上搜索之后,又加上自己的学习,将源代码贴在下面。
列的要求,在每个单元格内,按A显示优,B显示良,C显示中,D显示及格,E显示不及格,同时每个单元格的值是A、B、C、D、E,而显示值是优、良、中、及格、不及格。本来DataGridViewCell的Value和FormattedValue属性是可能完成这个任务的,不过该属性不是即时转换的,比如你输入A,离开当前编辑控件时,Value值这才传递给DataGridViewCell,然后才会显示FormattedValue为优(这是实现过程),用户看到的则是,你按了A,编辑控件显示的还是A,直到换到其它单元格,刚才的单元格才会显示为优,这样的界面不是很友好,所以才萌生了重新定义列的想法。
自定义列的实现过程。
第一步:自定义一个列,将自定义的单元格暴露给这个列。
第二步:自定义单元格,将自定义的编辑控件暴露给这个单元格。(说明,在DataGridView执行BeginEdit()前,会显示的就是这个单元格,但是这时候并没有进入编辑状态)
第三步:自定义编辑控件,并实现接口函数。(说明,这个就是BeginEdit()后,进入的单元格,在DataGridViewColumn中,一列所显示的单元格其实是一个控件,说白点,就是进入编辑状态后,将Cell中的值传递给一个控件,然后由这个控件对值进行编辑,完成后再将值返回给Cell,也就是说,这一列其实用的是一个控件,不管你有多少个单元格,如果有多列是同一种列,那么这多个列都是同一个控件,再说白点,比如我所有列都是DataGridViewTextBoxColumn,那么我第一行第三列进入编辑状态后和第二行第一列进入编辑状态后打开的是同一个控件,只是传给控件的值不同罢了。)
第四步:由于系统自带的TextBox控件不能满足我的要求,所以上一步所编辑的控件其实是继承自我自定义的TextBox控件。
下面是源代码,有些过程是我这里的特殊要求,不是必须的请注意。
1、DataGridViewLevelTextBoxColumn 即自定义列,它继承自DataGridViewTextBoxColumn。
2、DataGridViewLevelTextBoxCell 即自定义单元格,它继承自DataGridViewTextBoxCell。这里需要说明的是由于我要求该单元格的Value为ABCDE,而显示为优、良、中、及格、不及格,所以我重写了SetLevelValue()、GetValue()、GetFormattedValue()方法,这三个方法是根据个人需要来的,除此之外,有一个方法是必须的即InitializeEditingControl方法,它将初始化你自定义的编辑控件,这里你必须将自身的Value传递给该控件,由于我使用的是TextBox控件,所以值给的是Text属性,你使用什么控件就应该给什么属性。
3、LevelTextBoxDataGridViewEditingControl 为自定义的编辑控件,它应该继承一个控件和实现一个IDataGridViewEditingControl接口,由于系统自带的TextBox控件不能满足我的要求,所以我继承的是我自定义的LevelTextBox 控件,IDataGridViewEditingControl接口中的大部分不需要修改,只有一个必须注意的地方就是重载的OnTextChanged事件,这是因为,你在本控件中修改的值如果没有this.EditingControlDataGridView.NotifyCurrentCellDirty(true);这样一下的话,将不会把值传递给DataGridViewCell,也就是说不管你修改了什么,DataGridViewCell的值都不会改变,必须通知DataGridView,意思就是“喂,DataGridView,我的值改了,你也要改一下。”至于为什么重载OnTextChanged事件,当然是因为我继承的是LevelTextBox 控件又继承自TextBox控件,如果你是其它控件就有可能是OnValueChanged了。
4、LevelTextBox 是我自定义的控件,它继承自TextBox控件,这里只重载了OnKeyDown和OnKeyPress两个事件,这是因为我要求控件按A即显示优,所以要重载OnKeyDown事件,至于为什么要重载OnKeyPress事件,朋友们试一下就知道了,它只做了一件事,就是e.Handled = true;表示按键过程执行完了,不要再执行接下来的其它按键事件了。
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace WinEasV2.Controls
{
public class DataGridViewLevelTextBoxColumn : DataGridViewTextBoxColumn
{
public DataGridViewLevelTextBoxColumn()
{
this.CellTemplate = new DataGridViewLevelTextBoxCell();
}
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
DataGridViewLevelTextBoxCell cell = value as DataGridViewLevelTextBoxCell;
if (value != null && cell == null)
{
throw new InvalidCastException("Value provided for CellTemplate must be of type TEditNumDataGridViewCell or derive from it.");
}
base.CellTemplate = value;
}
}
}
public class DataGridViewLevelTextBoxCell : DataGridViewTextBoxCell
{
public DataGridViewLevelTextBoxCell()
{
}
private static Type defaultEditType = typeof(LevelTextBoxDataGridViewEditingControl);
private static Type defaultValueType = typeof(System.String);
public override Type EditType
{
get { return defaultEditType; }
}
public override Type ValueType
{
get
{
Type valueType = base.ValueType;
if (valueType != null)
{
return valueType;
}
return defaultValueType;
}
}
/// <summary>
/// 附加并初始化寄宿的编辑控件。
/// </summary>
/// <param name="rowIndex"></param>
/// <param name="initialFormattedValue"></param>
/// <param name="dataGridViewCellStyle"></param>
public override void InitializeEditingControl(int rowIndex, object
initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
// Set the value of the editing control to the current cell value.
base.InitializeEditingControl(rowIndex, initialFormattedValue,
dataGridViewCellStyle);
LevelTextBoxDataGridViewEditingControl ctl =
DataGridView.EditingControl as LevelTextBoxDataGridViewEditingControl;
ctl.Text =(string) SetLevelValue();
}
protected object SetLevelValue()
{
switch (this.Value.ToString())
{
case "A":
return "优";
case "B":
return "良";
case "C":
return "中";
case "D":
return "及格";
case "E":
return "不及格";
default:
return "";
}
}
protected override object GetValue(int rowIndex)
{
switch (base.GetValue(rowIndex).ToString())
{
case "优":
return "A";
case "良":
return "B";
case "中":
return "C";
case "及格":
return "D";
case "不及格":
return "E";
default:
return "";
}
}
protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, System.ComponentModel.TypeConverter valueTypeConverter, System.ComponentModel.TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
{
switch (base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context).ToString())
{
case "A":
return "优";
case "B":
return "良";
case "C":
return "中";
case "D":
return "及格";
case "E":
return "不及格";
default:
return "";
}
}
}
public class LevelTextBox : TextBox
{
public LevelTextBox() : base() { }
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
switch (e.KeyCode)
{
case Keys.A:
{
this.Text = "优";
e.Handled = true;
break;
}
case Keys.B:
{
this.Text = "良";
e.Handled = true;
break;
}
case Keys.C:
{
this.Text = "中";
e.Handled = true;
break;
}
case Keys.D:
{
this.Text = "及格";
e.Handled = true;
break;
}
case Keys.E:
{
this.Text = "不及格";
e.Handled = true;
break;
}
default:
{
this.Text = "";
e.Handled = true;
break;
}
}
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
e.Handled = true;
}
}
public class LevelTextBoxDataGridViewEditingControl : LevelTextBox, IDataGridViewEditingControl
{
private DataGridView dataGridView; // grid owning this editing control
private bool valueChanged = false; // editing control's value has changed or not
private int rowIndex; // row index in which the editing control resides
#region IDataGridViewEditingControl 成员
public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
{
this.Font = dataGridViewCellStyle.Font;
this.TextAlign = HorizontalAlignment.Center;
}
public DataGridView EditingControlDataGridView
{
get
{
return this.dataGridView;
}
set
{
this.dataGridView = value;
}
}
public object EditingControlFormattedValue
{
get
{
return GetEditingControlFormattedValue(DataGridViewDataErrorContexts.Formatting);
}
set
{
this.Text = (string)value;
}
}
public int EditingControlRowIndex
{
get
{
return this.rowIndex;
}
set
{
this.rowIndex = value;
}
}
public bool EditingControlValueChanged
{
get { return this.valueChanged; }
set { this.valueChanged = value; }
}
public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey)
{
switch (keyData & Keys.KeyCode)
{
case Keys.Right:
case Keys.Left:
case Keys.Down:
case Keys.Up:
case Keys.Home:
case Keys.End:
case Keys.Delete:
return true;
}
return !dataGridViewWantsInputKey;
}
public Cursor EditingPanelCursor
{
get { return Cursors.Default; }
}
public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
{
return this.Text;
}
public void PrepareEditingControlForEdit(bool selectAll)
{
}
public bool RepositionEditingControlOnValueChange
{
get { return false; }
}
protected override void OnTextChanged(EventArgs e)
{
valueChanged = true;
this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
base.OnTextChanged(e);
}
#endregion
}
}