定制DataGridView的数值编辑元素:Edit Control、Column与Cell

定制DataGridView的数值编辑元素:Edit Control、Column与Cell

点击查看大图
图1. 数值编辑DataGridView运行截图

引言

  本文将探讨在数值编辑应用中如何定义DataGridView的元素,如:编辑控件(Edit control)、表格列(Column)和单元格(Cell),从而具有如下功能:

  • 在定制表格列中可以设置小数位长度(0表示整数,最大长度为6);
  • 是否允许输入负号(可以是负数);
  • 当数值为0时是否显示null;
  • 支持鼠标上下文的剪切/复制/粘贴/删除操作;
  • 支持Ctrl+X、Ctrl+C、Ctrl+V快捷键操作;
  • 支持DataGridView内置的排序操作。

背景

  在数值编辑应用中已经有许多的定制表格列、单元格和表格的解决方案,经典的是Build a Custom NumericUpDown Cell and Column for the DataGridView Control(有笔者的翻译文章),该文深入、详细及分步骤地描述了DataGridView中的编辑控件、表格列与单元格的实现,其中的编辑控件基于标准的NumericUpDown,但却有如下一些不足:

  • 可以多次输入小数点;
  • 可以多次输入负号;
  • 在上下文菜单或快捷键中可以粘贴非数字字符;
  • 直接给单元格整数和小数值时,可能引起排序异常。

  许多的解决方案与上文类似,只处理键盘输入,较少支持鼠标上下文菜单中的剪切、复制、粘贴和删除操作,也较少处理快捷键如Strl+X、Ctrl+C和Ctrl+V的操作。

主要步骤

  本文根据Build a Custom NumericUpDown Cell and Column for the DataGridView Control(译文), 并使用笔者自己的开源倥件TNumEditBox作为编辑控件,定制编辑控件、表格列和单元格。其中的核心实现是,必须基于TNumEditBox创建编辑控件,然后定制DataGridView的表格列和单元格。主要步骤包括:

  • 从TNumEditBox和标准的IDataGridViewEditingControl派生TNumEditDataGridViewEditingControl类:
    • 实现IDataGridViewEditingControl接口的全部方法和属性;
    • 重写TNumEditBox的OnKeyPress(),在键盘输入时给DataGridView发值改变通知;
    • 重写TNumEditBox的OnTextChanged(),在Text改变时通知DataGridView。
  • 从DataGridViewTextBoxColumn派生TNumEditDataGridViewColumn类,并公开定制单元格的三个属性:DecimalLength、AllowNegative与ShowNullWhenZero;
  • 从DataGridViewTextBoxCell派生TNumEditDataGridViewCell类:
    • 重写两个属性:EditType与ValueType。属性EditType表示编辑控件的类型,即typeof(TNumEditDataGridViewEditingControl),属性ValueType表示单元格的值的类型,即typeof(decimal);
    • 重写5个方法:InitializeEditingControl、DetachEditingControl、SetValue、Clone与GetFormattedValue。InitializeEditingControl与DetachEditingControl方法处理编辑控件的初始化和清理工作,SetValue方法转换直接赋给单元格的值为decimal型,GetFormattedValue方法提供需要的格式化文本,Clone方法用在取消共享单元格的情况;
    • 定义3个属性:DecimalLength、AllowNegative与ShowNullWhenZero。

  事实上,上面引用的文章已经详细讨论了这些步骤和实现,但我们不必完全按照其它们的做法,因为我们使用TNumEditBox取代NumericUpDown作编辑控件,该控件与DataGridViewTextBoxEditingControl一样都派生自TextBox。当然,我们也不需要处理快捷键和上下文菜单,因为这些编辑操作由TNumEditBox完成。

关键点
我们指出一些与引用文不同的技术关键点。

1)重写TNumEditDataGridViewCell类的SetValue方法

  当我们直接给DataGridView的单元格赋值时,如:dataGridView1.Rows[0].Cells[0].Value = 1,将调用SetValue方法。该方法自动推断获得的值类型,即是说,如果赋1认为是整数,赋1.1则认为是实数。这样,当给某DataGridView列赋值1与1.1时,该列将有整数和实数,此时点击列表头排序将抛出异常,因为我们没有实现整数与实数的IComparer接口。

  由于DataGridViewTextBoxCell没有公开属性Value,我们只有重写SetValue方法: 

protected override bool SetValue(int rowIndex, object value){
    decimal val = 0.0m;
    try
    {
        val = Math.Round(System.Convert.ToDecimal(value), m_decimalLength);
    }
    catch { }
    return base.SetValue(rowIndex, val);
}

  我们转换所有赋给单元格的值为decimal型。我们不需要当心重写方法的性能问题,因为只有直接给单元格赋值时才调用该方法,在编辑或绑定数据源时均不会调用它。

2)定义TNumEditDataGridViewCell类的ShowNullWhenZero属性

  通常,DataGridView单元格值0时显示为0或 0.00等等,我们希望类似null时不显示该数值,特别是在DataGridView有许多0时的情况。这里,我们在TNumEditDataGridViewCell类中定义属性ShowNullWhenZero,要求与null一样处理0,于是我们重写GetFormattedValue方法: 

protected override object GetFormattedValue(object value, int rowIndex,ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, 
TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context){
    object baseFormattedValue = base.GetFormattedValue(value, rowIndex, ref cellStyle,        valueTypeConverter, formattedValueTypeConverter, context);
    string formattedText = baseFormattedValue as string;
    if (value == null || string.IsNullOrEmpty(formattedText)) // behave like null
    {
        return baseFormattedValue;
    }
    Decimal unformattedDecimal = System.Convert.ToDecimal(value); // 123.1 to "123.1"
    Decimal formattedDecimal = System.Convert.ToDecimal(formattedText); // 1.1 to "1.12" 如果DecimalLength=2
    if (unformattedDecimal == 0.0m && m_showNullWhenZero)
    {
        return base.GetFormattedValue(null, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);
    }
    if (unformattedDecimal == formattedDecimal)
    {
        return formattedDecimal.ToString("F" + m_decimalLength.ToString());
    } 
   return formattedText;
}

使用源码

  解包TNumEditDataGridViewElements.zip后,如果安装了VS2005/2008,我们可以双击解决方案文件TNumEditDataGridViewElements.sln浏览演示项目,或者运行子文件夹/bin/下的TNumEditDataGridViewEleentsDemo.exe观看与测试它们。下面是一些关于类文件和创建DataGridView表格列步骤的说明。

1)两个C#类文件

压缩包有两个C#类文件:

  • TNumEditBox.cs包含定制的TextBox数值编辑控件,它的实现可以参考www.codeproject.com上笔者的介绍, 该控件是DataGridView的编辑控件;
  • TNumEditDataGridViewElements.cs包含三个定制的DataGridView元素类,即:TNumEditDataGridViewEditingControl、 TNumEditDataGridViewColumn与TNumEditDataGridViewCell。

2)使用步骤

我们可以在应用项目中按如下步骤使用定制的表格元素:

  • 创建一个应用解决方案(solution)或项目,在项目中包括TNumEditBox.cs与TNumEditDataGridViewElements;
  • 在窗体控件上添加一个标准的DataGridView控件;
  • 增加并选择定制的表格列TNumEditDataGridViewColumns,如图2所示:

    图2. 选择DataGridView定制表格列
  • 定义表格列的TNumEditDataGridViewColumn的属性,即定义属性DecimalLength、AllowNegative与ShowNullWhenZero的值,如图3所示:

    图3. 定义定制表格列的属性值

好了,我们可以在应用中测试、运行与欣赏DataGridView定制元素了!

结论

  在Windows Forms中,DataGridView是一个功能强大的数据显示与编辑控件,我们希望它有一个方便与标准的数值处理方式。通常,我们定制一个或多个DataGridView核心元素。在TNumEditBox基础上,根据Build a Custom NumericUpDown Cell and Column for the DataGridView Control给出的方法和步骤,我们提供了一个定制DataGridView元素的解决方案,包括:编辑控件、表格列和单元格。我们方案的关键特点是:支持鼠标上下文菜单操作及快捷键。欢迎任何评论和建议。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值