VB.NET学习笔记:自定义控件之扩展DataGridViewColumnHeaderCell类增加CheckBox全选复选框
发布日期:2021-06-29 11:32:11
浏览次数:2
分类:技术文章
本文共 11874 字,大约阅读时间需要 39 分钟。
测试环境:windows 7和Microsoft Visual Studio 2015
VB.NET虽然提供了大量控件供我们使用,但很多控件仅提供最基础的功能。比如用DataGridView控件可以非常方便显示或操作数据库数据,我们可以在首列添加DataGridViewCheckBoxColumn列进行全选或全不选操作,但Datagridview控件并没有提供我们平时用的全选或取消全选的复选框,他的表头就只有这一列的名称,这样会影响用户的使用体验。这就需要我们对DataGridViewCheckBoxColumn列的列头进行扩展,创建符合使用要求的自定义控件。 一、自定义控件介绍 VB.NET中的窗体(WinFrom)自定义控件大致有三种形式: 1、组合控件(CompositeControls):继承自UserControl类,将目前现有的控件根据需要组合到一起形成一个新的控件。 2、扩展控件(ExtendedControls):继承自.NET类库中已有的控件,添加一些新的属性和方法来扩展原有控件。 3、自定义控件(CustomControls):继承自Control类,不提供控件特定的功能或图形界面,控件的绘制全部由用户定义。 二、扩展DataGridViewColumnHeaderCell类 可以在DataGridViewCheckBoxColumn列的列头拉一个CheckBox来实现全选全不选,但CheckBox的位置不好调控。最好的方法是扩展DataGridViewColumnHeaderCell类,在列头绘制一个复选框checkbox控件,通过定义checkbox鼠标单击事件来实现行的全选或取消全选。 效果如下图所示: 1、新建一个windows窗体应用程序项目。 为项目添加新项,取名DataGridViewCheckBoxColumnHeaderCellEx,类库。如下图所示整个项目包含一个类库和一个窗体。 2、用下面代码替换类库DataGridViewCheckBoxColumnHeaderCellEx.vb中自动生成的代码。Option Strict OnOption Infer OffOption Explicit On'Imports System'Imports System.Collections.Generic'Imports System.Text'Imports System.Windows.Forms'Imports System.DrawingImports System.Windows.Forms.VisualStylesImports System.Runtime.InteropServices#Region "扩展表头单元格"Public Class DataGridViewCheckBoxColumnHeaderCellEx Inherits DataGridViewColumnHeaderCell ' 委托处理DataGridViewCheckBoxClickedHandler事件 Public Delegate Sub DataGridViewCheckBoxClickedHandler(ByVal columnIndex As Integer, ByVal isCheckedAll As Boolean) Public Event OnCheckBoxClicked As DataGridViewCheckBoxClickedHandler#Region "属性" '''''' 标识本列是否全选,方便在Cell中获取 ''' '''Public ReadOnly Property IsCheckedAll As Boolean Get Return CheckedAllState = CheckState.Checked End Get End Property Private m_checkedAllState As CheckState = CheckState.Unchecked ''' ''' 全选按钮状态 ''' '''Public Property CheckedAllState As CheckState Get Return m_checkedAllState End Get Set(ByVal value As CheckState) m_checkedAllState = value End Set End Property ''' ''' 用于标识当前的checkbox状态 ''' Protected m_checkboxState As CheckBoxState = CheckBoxState.UncheckedNormal '''''' 是否是鼠标经过的这种hot状态,不是即为normal ''' Protected m_isHot As Boolean = False '''''' checkbox按钮区域 ''' Protected m_chkboxRegion As Rectangle '''''' 相对于本Headercell的位置 ''' Protected m_absChkboxRegion As Rectangle#End Region#Region "重绘" '''''' 在本Headercell绘制CheckBox控件 ''' ''' ''' ''' ''' ''' ''' ''' ''' ''' ''' ''' Protected Overloads Overrides Sub Paint(ByVal graphics As Graphics, ByVal clipBounds As Rectangle, ByVal cellBounds As Rectangle, ByVal rowIndex As Integer, ByVal dataGridViewElementState As DataGridViewElementStates, ByVal value As Object, ByVal formattedValue As Object, ByVal errorText As String, ByVal cellStyle As DataGridViewCellStyle, ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, ByVal paintParts As DataGridViewPaintParts) MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, "", "", errorText, cellStyle, advancedBorderStyle, paintParts) Me.m_chkboxRegion = GetSmallRectOfRectangle(cellBounds, CheckBoxRenderer.GetGlyphSize(graphics, CheckBoxState.UncheckedNormal), m_absChkboxRegion) Me.RenderCheckBox(graphics) End Sub '''''' 按当前的checkbox状态重绘checkbox ''' ''' Protected Sub RenderCheckBox(ByVal graphics As Graphics) If m_isHot Then RenderCheckBoxHover(graphics) Else RenderCheckBoxNormal(graphics) End If CheckBoxRenderer.DrawCheckBox(graphics, m_chkboxRegion.Location, m_checkboxState) End Sub '''''' 标识checkbox状态(normal) ''' ''' Protected Sub RenderCheckBoxNormal(ByVal graphics As Graphics) Select Case m_checkedAllState Case CheckState.Unchecked Me.m_checkboxState = CheckBoxState.UncheckedNormal Case CheckState.Indeterminate Me.m_checkboxState = CheckBoxState.MixedNormal Case CheckState.Checked Me.m_checkboxState = CheckBoxState.CheckedNormal End Select End Sub '''''' 标识checkbox状态(hot) ''' ''' Protected Sub RenderCheckBoxHover(ByVal graphics As Graphics) Select Case m_checkedAllState Case CheckState.Unchecked Me.m_checkboxState = CheckBoxState.UncheckedHot Case CheckState.Indeterminate Me.m_checkboxState = CheckBoxState.MixedHot Case CheckState.Checked Me.m_checkboxState = CheckBoxState.CheckedHot End Select End Sub '''''' 获取本Headercell的Rectangle及其中的checkbox控件的Rectangle ''' ''' ''' checkbox控件的Size ''' checkbox控件的Rectangle '''Protected Shared Function GetSmallRectOfRectangle(ByVal rectangle As Rectangle, ByVal smallSize As Size, ByRef absRectangle As Rectangle) As Rectangle Dim rect As Rectangle = New Rectangle() absRectangle = New Rectangle() absRectangle.Size = smallSize absRectangle.X = CType(((rectangle.Width - smallSize.Width) / 2), Integer) absRectangle.Y = CType((rectangle.Height - smallSize.Height) / 2, Integer) rect.Size = smallSize rect.X = absRectangle.X + rectangle.X rect.Y = absRectangle.Y + rectangle.Y Return rect End Function#End Region#Region "事件" Protected Overrides Sub OnMouseMove(ByVal e As DataGridViewCellMouseEventArgs) MyBase.OnMouseMove(e) If IsInCheckRegion(e.Location) Then m_isHot = True Me.DataGridView.InvalidateCell(Me) End Sub Protected Overrides Sub OnMouseLeave(ByVal rowIndex As Integer) MyBase.OnMouseLeave(rowIndex) m_isHot = False Me.DataGridView.InvalidateCell(Me) End Sub Protected Overrides Sub OnMouseDown(ByVal e As DataGridViewCellMouseEventArgs) MyBase.OnMouseDown(e) m_isHot = IsInCheckRegion(e.Location) Me.DataGridView.InvalidateCell(Me) End Sub Protected Overloads Overrides Sub OnMouseClick(ByVal e As DataGridViewCellMouseEventArgs) Dim value As Boolean = False If IsInCheckRegion(e.Location) Then Select Case m_checkedAllState Case CheckState.Unchecked m_checkedAllState = CheckState.Checked value = True Case CheckState.Indeterminate m_checkedAllState = CheckState.Checked value = True Case CheckState.Checked m_checkedAllState = CheckState.Unchecked value = False End Select Me.Value = value '引发事件 RaiseEvent OnCheckBoxClicked(e.ColumnIndex, value) Me.DataGridView.InvalidateCell(Me) End If MyBase.OnMouseClick(e) End Sub ''' ''' 是否在checkbox按钮区域 ''' ''' '''Protected Function IsInCheckRegion(ByVal p As Point) As Boolean Return Me.m_absChkboxRegion.Contains(p) End Function#End Region ''' ''' checkbox列的单元格改变事件 ''' ''' Friend Sub OnCheckBoxCellCheckedChange(ByVal columnIndex As Integer) If columnIndex <> Me.ColumnIndex Then Return Dim existsChecked As Boolean = False, existsNoChecked As Boolean = False For Each row As DataGridViewRow In Me.DataGridView.Rows existsChecked = existsChecked Or CType(row.Cells(columnIndex).EditedFormattedValue, Boolean) existsNoChecked = existsNoChecked Or Not CType(row.Cells(columnIndex).EditedFormattedValue, Boolean) Next Dim oldState As CheckState = Me.CheckedAllState If existsChecked Then If existsNoChecked Then Me.CheckedAllState = CheckState.Indeterminate Else Me.CheckedAllState = CheckState.Checked End If Else Me.CheckedAllState = CheckState.Unchecked End If If oldState <> Me.CheckedAllState Then Me.DataGridView.InvalidateCell(Me) End SubEnd Class#End Region
代码重点解读:
(1)、新DataGridViewCheckBoxColumnHeaderCellEx类,继承自DataGridViewColumnHeaderCell。Public Class DataGridViewCheckBoxColumnHeaderCellEx Inherits DataGridViewColumnHeaderCellEnd Class
心得:通常组合控件用“用户控件”;;自定义控件用“组件类”或“自定义控件”;;扩展没有单独界面控件用“类”,如本例,DataGridViewColumnHeaderCell类不能单独显示界面,只能在DataGridView控件显示时一同显示,所以扩展该类的DataGridViewCheckBoxColumnHeaderCellEx类只能用“类”;而扩展有单独界面控件需用“组件类”或“自定义控件”。其中奥妙你只要试试就知道了。
(2)、委托和事件' 委托处理DataGridViewCheckBoxClickedHandler事件 Public Delegate Sub DataGridViewCheckBoxClickedHandler(ByVal columnIndex As Integer, ByVal isCheckedAll As Boolean) Public Event OnCheckBoxClicked As DataGridViewCheckBoxClickedHandler
在鼠标单击时触发该事件。
Protected Overloads Overrides Sub OnMouseClick(ByVal e As DataGridViewCellMouseEventArgs) '引发事件 RaiseEvent OnCheckBoxClicked(e.ColumnIndex, value) End Sub
在窗体引用DataGridViewCheckBoxColumnHeaderCellEx类时订阅事件。
'订阅事件 AddHandler checkbox1.OnCheckBoxClicked, AddressOf Checkbox_OnCheckboxClicked
(3)、一个函数过程返回2个值。如下代码Return rect返回本Headercell的Rectangle,absRectangle返回绘制的checkbox控件的Rectangle。
'''''' 获取本Headercell的Rectangle及其中的checkbox控件的Rectangle ''' ''' ''' checkbox控件的Size ''' checkbox控件的Rectangle '''Protected Shared Function GetSmallRectOfRectangle(ByVal rectangle As Rectangle, ByVal smallSize As Size, ByRef absRectangle As Rectangle) As Rectangle Dim rect As Rectangle = New Rectangle() absRectangle = New Rectangle() absRectangle.Size = smallSize absRectangle.X = CType(((rectangle.Width - smallSize.Width) / 2), Integer) absRectangle.Y = CType((rectangle.Height - smallSize.Height) / 2, Integer) rect.Size = smallSize rect.X = absRectangle.X + rectangle.X rect.Y = absRectangle.Y + rectangle.Y Return rect End Function
三、调用DataGridViewCheckBoxColumnHeaderCellEx类
用如下代码替换Form1.vb里自动生成的代码。Public Class Form1 '定义一眉头Checkbox1从类DataGridViewCheckBoxColumnHeaderCellEx构造而来 Private checkbox1 As New DataGridViewCheckBoxColumnHeaderCellEx Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load '新列增加一个控件Checkbox1 Me.DataGridView1.Columns(0).HeaderCell = checkbox1 Me.DataGridView1.Rows.Add(5) Me.DataGridView1.AllowUserToAddRows = False '订阅事件 AddHandler checkbox1.OnCheckBoxClicked, AddressOf Checkbox_OnCheckboxClicked End Sub Private Sub Checkbox_OnCheckboxClicked(ByVal columnIndex As Integer, ByVal isCheckedAll As Boolean) Me.DataGridView1.EndEdit() '结束编辑操作 For Each Row As DataGridViewRow In Me.DataGridView1.Rows Row.Cells(columnIndex).Value = isCheckedAll Next End Sub '''''' 单击列单元格的内容事件 ''' ''' ''' Private Sub DataGridView1_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick Me.DataGridView1.EndEdit() '结束编辑操作 Me.checkbox1.OnCheckBoxCellCheckedChange(e.ColumnIndex) End SubEnd Class
代码重点解读:
在处理单击列头实现全选或取消全选操作、单击单元格操作时,必须结束单元格的编辑状态,否则无法正确获取修改后的单元格内容,造成处于编辑状态的单元格无法改变勾选状态或在单击单元格时列头的显示与实际不相符。Me.DataGridView1.EndEdit() '结束编辑操作在参考的文章里看到还要新建一个datagridviewCheckboxHeaderEventArgs类,继承自EventArgs类,用在在checkbox单击事件中提供类头checkbox的选择状态。我的项目里没有用上,具体有什么作用不详,望能得到指点。
'定义包含列头checkbox选择状态的参数类Class datagridviewCheckboxHeaderEventArgs Inherits EventArgs Private checkedState As Boolean = False Public Property CheckedState As Boolean Get Return checkedState End Get Set(ByVal value As Boolean) checkedState = value End Set End PropertyEnd Class
本文参考以下文章:
1、 2、 学习过程得到网友的帮助,表示感谢!转载地址:https://blog.csdn.net/zyjq52uys/article/details/85272588 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年04月15日 06时27分15秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
广度+深度:岛屿的最大面积/岛屿数量
2019-04-29
torch 模型运行时间与forward没对应的可能原因
2019-04-29
130. 被围绕的区域
2019-04-29
欧式距离、余弦相似度和余弦距离
2019-04-29
transform 等效转换(参考源码)
2019-04-29
Docker学习(二):Docker基本操作(控制容器)
2019-04-29
Unity之C#学习笔记(0):环境配置与上手 HelloWorld
2019-04-29
高并发高可用秒杀系统(一)
2019-04-29
php如何将base64数据流文件转换为图片文件?
2019-04-29
JavaScript 的addEventListener() 事件监听详解!
2019-04-29
JavaScript的DOMContentLoaded事件和load的区别?
2019-04-29
PHP+JavaScript实现图片预览上传功能开发!
2019-04-29
JSONView - Chrome插件安装详解!(谷歌浏览器插件)!
2019-04-29
上传图片到阿里云OSS和获取上传图片的url的详解 !
2019-04-29
webstorm 和 phpstorm 有什么区别呢?做 WEB 开发用哪个好?
2019-04-29
常见位运算
2019-04-29
武大学生用python敲出樱花开放 | 附源码
2019-04-29
【中文教程】简单粗暴入门TensorFlow 2.0 | 北大学霸出品
2019-04-29
经典面试题:如何保证缓存与数据库的双写一致性?
2019-04-29
一份来自亚马逊工程师的Google面试指南,GitHub收获9.8万星,已翻译成中文
2019-04-29