DataGridViewColumn 承载 MaskedTextBox
如何在 DataGridViewColumn 中承载 MaskedTextBox

引言
您想在 DataGridViewColumn
中使用 MaskedTextBox
吗?就是它了。向 DataGridView
添加一个 DataGridViewMaskedTextColumn
并设置 Mask
字符串。然后您将获得一个以该 Mask
作为 EditingControl
的 MaskedTextBox
。
背景
.NET Framework 只为 DataGridView
列提供了一个标准的 TextBox
。通过数据绑定,限制输入为数字并不成问题,例如可以通过 DataGridView.EditingControlShowing
事件设置 TextBox.CharacterCasing
。更复杂的限制可以在 MaskedTextBox
中实现。因此,在 DataGridViewColumn
中承载 MaskedTextBox
是很有用的。
Yildirim Kocdag 的解决方案 Generic DataGridView(更新于 2008 年 1 月 24 日)包含一个 MaskedTextColumn
,但如果需要添加两个(或更多)具有不同 Mask
字符串的 MaskedTextColumn
,则存在一个问题:在这种情况下,控件只保留一个掩码,因为 DataGridView
为所有列都只包含一个特定的 EditingControl
。
Microsoft 的示例 如何:在 Windows Forms DataGridView 单元格中承载控件 提供了一种创建自定义 DataGridViewColumn
类的方法。但它不够完善,因为 Mask
属性需要实现 Clone
方法,而示例不需要。在我使用 Lutz Roeder's Reflector 研究了所有原始 DataGridView
类之后,我找到了我的解决方案。
Using the Code
MaskedTextColumn
解决方案由三个组合类组成,并由一个属性类添加。
类在设计器中用于调用现有描述。有关详细信息,请参阅 此处。ReferencedDescriptionAttribute
MaskedText
类被包含在您自己的 *ExtendedControls.dll 程序集中*,或者您直接存储准备好的 DLL。添加对此程序集的引用,您就可以使用 DataGridViewMaskedTextColumn
。您只需要使用这个类;DataGridViewMaskedTextCell
类和 DataGridViewMaskedTextControl
类由框架自身自动使用。
通过代码工作
像任何其他 DataGridViewColumn
一样,向您的 DataGridView
添加一个 DataGridViewMaskedTextColumn
并设置 Mask
属性
using JThomas.Controls;
// create a new column and set a mask using a minimum of 4 and a maximum of 7 digits
DataGridViewMaskedTextColumn column = new DataGridViewMaskedTextColumn("0000999");
column.DataPropertyName = "Number";
column.HeaderText = "Nummer"; // German text
column.Name = "column";
column.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
column.Width = 70;
// add this column to the DataGridView dgv
dgv.Columns.Add(column);
通过设计器工作
在添加对 *ExtendedControls.dll 程序集* 的引用后,您可以打开 IDE 并选择一个 DataGridViewMaskedTextColumn
作为 DataGridViewColumn
- 无论是在“编辑列”窗口中,如上图所示,还是在“添加列”窗口中。您可以在那里设置 Mask
字符串。
掩码详细信息
请在 SDK 文档中查看 MaskedTextBox.Mask
属性的所有 Mask
可能性。
工作原理
正如 Microsoft 的示例所示,我们需要定义三个类。
DataGridViewMaskedTextColumn
此类与原始 DataGridViewTextBoxColumn
类一样,派生自 DataGridViewColumn
。我们必须实现自己的派生,因为 MaxInputLength
属性在 MaskedTextBox
实例中无效。它包含标准的构造函数和另一个直接设置 Mask
字符串的构造函数。
// use the Bitmap of MaskedTextBox
[System.Drawing.ToolboxBitmap(typeof(System.Windows.Forms.MaskedTextBox))]
public class DataGridViewMaskedTextColumn : DataGridViewColumn
{
public DataGridViewMaskedTextColumn() : this(String.Empty) {}
public DataGridViewMaskedTextColumn(string maskString)
: base(new DataGridViewMaskedTextCell())
{
SortMode = DataGridViewColumnSortMode.Automatic;
Mask = maskString;
}
一些方法和属性与 DataGridViewTextBoxColumn
类相同,派生而来。
public override string ToString() { ... }
public override DataGridViewCell CellTemplate { get; set; }
public new DataGridViewColumnSortMode SortMode { get; set; }
private DataGridViewMaskedTextCell MaskedTextCellTemplate { get; }
为了使用 Mask
属性,我们必须添加 Clone
方法。
public override object Clone()
{
DataGridViewMaskedTextColumn col = (DataGridViewMaskedTextColumn)base.Clone();
col.Mask = Mask;
col.CellTemplate = (DataGridViewMaskedTextCell)this.CellTemplate.Clone();
return col;
}
主要工作是在此列的每个 DataGridViewMaskedTextCell
中使用 Mask
字符串。因此,我们不仅可以定义一个简单的 getter 和 setter,而且必须像 DataGridViewTextBoxColumn
对其 MaxInputLength
属性所做的那样,将值存储在每个包含的 DataGridViewCell
中。
[Category("Masking")]
// use the MaskedTextBox.Mask description
[JThomas.Extensions.ReferencedDescription(typeof
(System.Windows.Forms.MaskedTextBox),"Mask")]
public string Mask
{
get { ... }
set {
if (Mask != value)
{
MaskedTextCellTemplate.Mask = value;
if (base.DataGridView != null)
{
DataGridViewRowCollection rows = base.DataGridView.Rows;
int count = rows.Count;
for (int i = 0; i < count; i++)
{
DataGridViewMaskedTextCell cell
= rows.SharedRow(i).Cells[base.Index]
as DataGridViewMaskedTextCell;
if (cell != null)
cell.Mask = value;
}
}
}
}
}
DataGridViewMaskedTextCell
此类可以从 DataGridViewTextBoxCell
类派生,因为非活动单元格的行为没有区别。只需要重写一些方法和属性,并适应当前的类和名称。主要工作是简单地添加 Clone
方法和 Mask
属性。
public override object Clone()
{
DataGridViewMaskedTextCell cell = base.Clone() as DataGridViewMaskedTextCell;
cell.Mask = this.Mask;
return cell;
}
private string mask;
public string Mask {
get { return mask == null ? String.Empty : mask; }
set { mask = value; }
}
DataGridViewMaskedTextControl
此类必须派生自
类,并实现 MaskedTextBox
接口。大多数成员的适应方式与 Microsoft 的示例类似。只需要使用 IDataGridViewEditingControl
string
值而不是 object
,以及使用 MaskedTextBox.Text
属性而不是 DateTimePicker.Value
属性。
最重要的定义如下:
public object EditingControlFormattedValue
{
get { return Text; }
set { if (value is string)
Text = (string)value;
}
}
public void ApplyCellStyleToEditingControl(
DataGridViewCellStyle dataGridViewCellStyle)
{
Font = dataGridViewCellStyle.Font;
// get the current cell to use the specific mask string
DataGridViewMaskedTextCell cell
= dataGridView.CurrentCell as DataGridViewMaskedTextCell;
if (cell != null) {
Mask = cell.Mask;
}
}
public void PrepareEditingControlForEdit(bool selectAll)
{
if (selectAll)
SelectAll();
else {
SelectionStart = 0;
SelectionLength = 0;
}
}
// MaskedTextBox event
protected override void OnTextChanged(System.EventArgs e)
{
base.OnTextChanged(e);
EditingControlValueChanged = true;
if (EditingControlDataGridView != null) {
EditingControlDataGridView.CurrentCell.Value = Text;
}
}
关注点
TextBox.CharacterCasing
不需要 DataGridViewMaskedTextColumn
,但可以按如下方式嵌入:
void DgvEditingControlShowing
(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (e.Control is TextBox) {
TextBox box = e.Control as TextBox;
// example: 2nd column requires upper case
box.CharacterCasing
= dgv.CurrentCell.ColumnIndex == 1
? CharacterCasing.Upper
: CharacterCasing.Normal;
}
}
可以在 DataGridViewMaskedText
解决方案中插入一个 DefaultValue
属性。另一方面,将默认值连接到数据实例很有用。您最好使用 DataColumn.DefaultValue
属性,或 DataTable.TableNewRow
事件,或 DataGridView.RowsAdded
事件,或 BindingNavigator.AddNewItem.Click
事件,或者其他类似的东西。
历史
- 2008/04/05:第一个版本