.NET组件控件实例编程系列——3.DataGridView列标题可编辑组件

在上一篇中介绍了用Label控件模拟网页链接的组件,实现原理只是简单的将Label控件的事件进行了处理。本篇中介绍的DataGridView列标题可编辑组件在对DataGridView控件的事件进行处理的同时,加入了更多的技巧。

首先介绍本示例要实现的效果。WinForm中的DataGridView控件只能对单元格进行编辑,但有时候需要对列标题进行编辑,即自定义列标题。本组件就是实现列标题编辑的功能,双击列标题即可进行编辑,支持键盘左右键移动编辑单元格。编辑效果如下图。(注:双击列标题对某些数据源会执行排序操作,如果需要避免,可以自行修改为通过右键菜单选择开始编辑。)

DataGridView列标题可编辑组件示例

上面介绍了需要实现什么效果,但DataGridView的列标题是不提供编辑的,那如何实现编辑呢?这里用了一个RichTextBox控件去模拟编辑状态,将RichTextBox控件覆盖到需要编辑的列标题上方,看起来就像是对列标题进行编辑一样。这个例子就比上一个稍微复杂一点,不仅仅是处理几个简单的事件了。下面就介绍实现的过程。

首先新建一个项目,选择项目类型为类库,输入项目名称DataGridViewColumnHeaderEditor,然后添加组件DataGridViewColumnHeaderEditor。具体的操作步骤在上一篇已经介绍过了,就不详细阐述。
和上一篇中介绍的组件一样,首先必须给组件指定一个操作目标。这里要操作的是DataGridView,所以添加一个DataGridView类型的属性,另外添加了一个属性指示是否允许编辑,代码如下:
上面提到了用一个RichTextBox控件去模拟编辑效果,那么这里就需要添加一个RichTextBox控件。切换到组件的设计视图,从工具箱中拖动一个RichTextBox控件到组件中。设置RichTextBox控件的相关属性,将MultiLine、TabStop和Visible均设置为False。
启用编辑的操作是双击列标题,那么就需要对DataGridView控件的列标题双击事件进行处理。上一篇中介绍了窗体背后的故事,是通过设置属性的时候绑定事件处理程序的,也提到了用另一种方法实现,那就是ISupportInitialize接口。本例就采用这种方法来把控件的事件和对应的事件处理程序绑定。

Code

 

下面介绍一下ISupportInitialize接口。参考MSDN中的介绍,ISupportInitialize接口:指定该对象支持对批初始化的简单的事务处理通知。该接口包含两个方法BeginInit和EndInit,在该接口的备注中有如下说明:
ISupportInitialize 允许控件为多组属性而优化。因此,可以在设计时初始化相互依赖的属性或批设置多个属性。
调用 BeginInit 方法用信号通知对象初始化即将开始。调用 EndInit 方法用信号通知初始化已完成。

下面做个试验,往一个窗体上放置一个DataGridView控件,回到窗体的设计器代码Designer.cs中,可以看到在InitializeComponent方法中有如下代码:

Code

可以看出这个接口的方法是在窗体初始化的时候被调用的。如果需要对控件或者组件进行初始化,可以在BeginInit中进行,如果需要在初始化完成之后进行其他相关的操作,可以在EndInit中进行。本例把绑定事件与处理方法的操作放在了EndInit中,代码如下:

Code

在EndInit方法中,首先判断目标控件是否为空,然后将RichTextBox添加到目标控件的父控件中并前置,这样才能在编辑的时候覆盖在DataGridView控件上。之后是ReloadSortedColumnList方法,该方法获取列对象列表,并且按照显示序号进行排序。因为DataGridViewColumn有两个序号,一个是Index,是在DataGridView控件的Columns中的序号,另一个是DisplayIndex,是实际显示的序号。用户可能调整列的顺序,有些列可能是隐藏的,如果从DataGridView控件的Columns属性中按Index操作可能发生错误。比如在DataGridView控件的Columns中Index为2的列可能DisplayIndex为0。用键盘操作编辑框从Index为3且DisplayIndex为3的列向左移动的时候,跳到序号为2的列上,显示给用户就是从第3列跳到第0列。最后就是将DataGridView控件的事件绑定到相关的事件处理方法上。以下就是事件处理方法的代码:

Code

从代码里可以看到,列增减以及序号改变都需要重新加载列表排序,双击则显示编辑效果,另一个就是DataGridView控件的滚动条操作。为什么需要对滚动条事件进行处理?因为这里是用一个RichTextBox控件模拟的编辑状态,如果不处理,列标题的位置变了,编辑框却还定在那里,就会错位了。而且列的坐标会随着滚动条操作发生改变,如果不记录滚动条的位置,在双击列标题时就会得到一个列标题的内部相对坐标,但RichTextBox是按照外部绝对坐标显示的,这样也会发生错位。而DataGridView控件没法直接获取滚动条的位移,所以只好在滚动条事件中记录滚动条的位移了。(注意:在其他带滚动条的控件中确定子控件的位置也需要考虑滚动条。
绑定好DataGridView控件的事件处理方法之后,就是对RichTextBox控件的操作了。编辑框需要处理键盘操作以实现移动和完成编辑的操作,对应方法是rtbTitle_KeyDown。编辑框失去焦点时也要作为编辑完成的动作,对应方法是rtbTtile_Leave方法。ShowHeaderEdit方法是显示编辑效果的,主要是确定编辑框的位置和大小,把对应列的标题显示到编辑框中。这里不允许输入空的标题,如果需要,可以根据实际情况修改代码。另外其中加入了一些事件,用来更加灵活控制编辑操作。关于事件,稍后再详细介绍。

Code

在上面对编辑框操作的相关方法中,又涉及到了对列对象的一些操作,比如获取相对坐标,左右移动时获取邻近显示的列。下面就是这些方法的代码。

Code

以上方法都比较简单,不再详细解释。下面就介绍事件。在类中声明了三个事件,代码如下:

Code

BeginEdit事件是在编辑开始的时候发生的,如果有一些列不允许编辑,则可以在该事件处理方法中捕获并取消。
EndingEdition事件是在编辑即将结束的时候发生的,如果用户输入的列标题不合理,可以取消结束编辑,强制用户继续编辑。
EndEdit事件是在编辑结束后发生的,通知外部被编辑的列的相关信息。
这些事件的类型都是ColumnHeaderEditEventHandler,如下是该事件委托的定义以及事件参数的定义。如果对事件和委托不是很了解,请先查阅相关资料,这里不作详细阐述。

小技巧——事件委托和事件参数相关
通常事件委托的名称定义为事件相关名称+EventHandler,比如MouseEventHandler,PaintEventHandler,CancelEventHandler,FormClosedEventHandler。事件委托一般包含两个参数格式,定义格式如public delegate void MyEventHandler(object sender, MyEventArgs e)。而事件参数一般定义为事件相关名称+EventArgs,比如DragEventArgs,ListChangedEventArgs,NavigateEventArgs,MouseEventArgs。事件参数中的属性一般是不可修改的,即没有set段,是通过构造函数指定的。如果需要通过参数影响事件的行为,则会存在set段。

Code

小技巧——引发事件的方法
如果在一个类中存在多个地方引发同一个事件,可以考虑用一个方法代替。因为引发事件之前都必须判断该事件委托是否为空,否则直接引发事件可能出错。示例如下:

Code

 

至此,组件的编码就完成了,类图如下。
DataGridViewColumnHeaderEditor类图
小技巧——查看类图的方法
对项目添加新项,选择“类关系图”,然后把需要查看的类从解决方案管理器中拖动到类图即可。也可以在类图中直接添加新项,用类图去设计类和其他对象。

编译一下。然后添加测试的Windows应用程序项目,在窗体上放置一个DataGridView控件,对该控件添加几列。然后拖动DataGridViewColumnHeaderEditor组件到窗体上,设置组件的TargetControl属性为之前添加的DataGridView控件。按F5运行,双击列标题即可编辑,回车或者用鼠标点击别处可完成编辑,也可以通过键盘左右方向键移动编辑框。

本例相比上一个例子,稍微复杂一点,添加了接口实现和自定义事件。这里也提供了一种间接解决问题的思路,虽然DataGridView控件本身不支持编辑列标题,但可以用一个RichTextBox去模拟编辑状态。通过这个例子,可以引申出其他解决方案,比如对树节点用下拉框编辑,用ListView或者DataGridView让下拉框显示多列等等。具体的应用就要靠自己实践了,希望这篇文章能给您带来收获。

另外在这个示例中有个问题没解决,那就是滚动条的操作,当编辑框移动到可视范围之外时,需要手动操作滚动条才能让编辑框显示。但是DataGridView不提供操作滚动条的方法,其他带滚动条的控件也不提供操作滚动条的方法。不知有没有哪位大侠知道方法?

代码下载:https://files.cnblogs.com/conexpress/TestDataGridViewColumnHeaderEditor.zip

posted @ 2009-03-06 10:37  Alex Leo  阅读(5427)  评论(5编辑  收藏  举报