65.9K
CodeProject 正在变化。 阅读更多。
Home

DataGridViewColumn 承载 MaskedTextBox

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.55/5 (20投票s)

2008年5月12日

CPOL

3分钟阅读

viewsIcon

228940

downloadIcon

8006

如何在 DataGridViewColumn 中承载 MaskedTextBox

引言

您想在 DataGridViewColumn 中使用 MaskedTextBox 吗?就是它了。向 DataGridView 添加一个 DataGridViewMaskedTextColumn 并设置 Mask 字符串。然后您将获得一个以该 Mask 作为 EditingControlMaskedTextBox

背景

.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 类,并实现 IDataGridViewEditingControl 接口。大多数成员的适应方式与 Microsoft 的示例类似。只需要使用 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:第一个版本
© . All rights reserved.