• .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

  • 相关阅读:
    Calling a parent window function from an iframe
    JSON with Java
    Posting array of JSON objects to MVC3 action method via jQuery ajax
    What's the difference between jquery.js and jquery.min.js?
    jquery loop on Json data using $.each
    jquery ui tabs详解(中文)
    DataTables warning requested unknown parameter
    Datatables 1.10.x在命名上与1.9.x
    jQuery 1.x and 2.x , which is better?
    DataTabless Add rows
  • 原文地址:https://www.cnblogs.com/conexpress/p/Component_Control_03.html
Copyright © 2020-2023  润新知