经过一段时间的努力,并参阅了很多大侠的源代码,重新改造了一下DataGrid控件。现将所有的源代码全部公布,以和朋友们共享。
'主要的功能有:
' 可以显示汉字标题、列宽、左边行号;
' 可以按照标题行排序;
' 可以设置脚注汇总行(排序后仍然在最后一行);
' 表格中有右键菜单;
' 可以根据各单元格的数据类型,自动设置显示格式;
' 对于日期时间数据,可以只显示日期,也可显示时间;
' 对于逻辑型数据,用CheckBox显示数据
'主要的属性是:
'.BqColorFootBack 设置脚注合计行的背景颜色,如果不设,则与表格背景一致
'.BqColorFootFont 设置脚注合计行的字体颜色,如果不设,则与表格字体一致
'.BqcNoReadOnlyMap 设置哪此字段是可以编辑的,如果不设,则所有字段只读
'.BqColumnHeader 设置表格中各显示列的汉字标题,如果不设,则标题为空
'.BqColumnMap 设置表格中各显示列的字段名,如果不设,则显示数据源中所有字段
'.BqColumnWidth 设置表格中各显示列的宽度,如果不设,则自动列宽
'.BqSetSource 设置表格的数据源dataview。设置好上面的属性后,就可以用此属性进行初始化了。
'.BqMsetSum 设置并返回聚合函数的值,并在表格最后脚注栏显示
'.BqpshowAllColumnS 设置是否整行选中
'.BqpshowAutoWidths 设置是否自动列宽
'.BqpShowNull 设置是否显示空值
'.BqpShowNumber 设置是否显示左边的行号
'.BqpShowTime 设置是否显示完整的时间,否则只显示年月日
'例如:
' With BqUDataGrid1
' .BqColumnMap = "ID1,BHranKdq,BHdq,BHparent,MCdq,YB,QH,ZD,PYdq,K_dele"
' .BqColumnHeader = "ID,级别编号,地区编号,上级编号,地区名称,邮政编码,电话区号,驻地,拼音代码,停用"
' .BqColumnWidth = "0,40,60,0,120,60,0,80,50,30,100,150,50,80,100,150,50,60,50"
' .BqcNoReadOnlyMap = "MCdq,YB,QH,"
' .BqColorFootBack = Brushes.White
' .BqColorFootFont = Brushes.Tomato
' .BqSetSource = ltv
' End With
'还需要改进的是:
' 1、红字条件。即给定一个符合where规则的条件表达式,让控件用红色显示满足条件的记录;
' 2、返回记录。即随时返回当前的记录datarow,从而确定当前记录中各字段的值,并且还能判断是否满足条件
' 3、左边行号。如果能够把左边行号与表中的记录号一一对应就好了。
Imports SystemImports System.CollectionsImports Microsoft.visualbasicImports System.ComponentModelImports System.DrawingImports System.DataImports System.Windows.FormsImports System.Text全新打造的最新的datagrid 作者:钱波#Region " 全新打造的最新的datagrid 作者:钱波 "'主要的功能有:' 可以显示汉字标题、列宽、左边行号、可以按照标题行排序,可以设置脚注汇总行(排序后仍然在最后一行)、表格中有右键菜单'主要的属性是:'.BqColorFootBack 设置脚注合计行的背景颜色,如果不设,则与表格背景一致'.BqColorFootFont 设置脚注合计行的字体颜色,如果不设,则与表格字体一致'.BqcNoReadOnlyMap 设置哪此字段是可以编辑的,如果不设,则所有字段只读'.BqColumnHeader 设置表格中各显示列的汉字标题,如果不设,则标题为空'.BqColumnMap 设置表格中各显示列的字段名,如果不设,则显示数据源中所有字段'.BqColumnWidth 设置表格中各显示列的宽度,如果不设,则自动列宽'.BqSetSource 设置表格的数据源dataview。设置好上面的属性后,就可以用此属性进行初始化了。'.BqMsetSum 设置并返回聚合函数的值,并在表格最后脚注栏显示'.BqpshowAllColumnS 设置是否整行选中'.BqpshowAutoWidths 设置是否自动列宽'.BqpShowNull 设置是否显示空值'.BqpShowNumber 设置是否显示左边的行号'.BqpShowTime 设置是否显示完整的时间,否则只显示年月日'例如:' With BqUDataGrid1' .BqColumnMap = "ID1,BHranKdq,BHdq,BHparent,MCdq,YB,QH,ZD,PYdq,K_dele"' .BqColumnHeader = "ID,级别编号,地区编号,上级编号,地区名称,邮政编码,电话区号,驻地,拼音代码,停用"' .BqColumnWidth = "0,40,60,0,120,60,0,80,50,30,100,150,50,80,100,150,50,60,50"' .BqcNoReadOnlyMap = "MCdq,YB,QH,"' .BqColorFootBack = Brushes.White ' .BqColorFootFont = Brushes.Tomato' .BqSetSource = ltv ' End With'还需要改进的是:' 1、红字条件。即给定一个符合where规则的条件表达式,让控件用红色显示满足条件的记录;' 2、返回记录。即随时返回当前的记录datarow,从而确定当前记录中各字段的值,并且还能判断是否满足条件' 3、左边行号。如果能够把左边行号与表中的记录号一一对应就好了。Public Class BqUDataGridClass BqUDataGrid Inherits System.Windows.Forms.DataGrid初始化时需要定义的属性和方法#Region " 初始化时需要定义的属性和方法 " Public WriteOnly Property BqColumnMap()Property BqColumnMap() As String Set(ByVal Value As String) lColumnMap = Value 'MGsubStrings(Value) End Set End Property ' Public WriteOnly Property BqColumnHeader()Property BqColumnHeader() As String Set(ByVal Value As String) lColumnHeader = Value End Set End Property Public WriteOnly Property BqColumnWidth()Property BqColumnWidth() As String Set(ByVal Value As String) lColumnWidth = Value End Set End Property Public WriteOnly Property BqcNoReadOnlyMap()Property BqcNoReadOnlyMap() As String Set(ByVal Value As String) lMapOnly = Value End Set End Property '非只读的列名,即可以编辑的字段,毕竟是少数 Public WriteOnly Property BqConditiona()Property BqConditiona() As String Set(ByVal Value As String) lredConditiona = Value End Set End Property '指定条件,分颜色显示的条件 Public WriteOnly Property BqConditionaMap()Property BqConditionaMap() As String Set(ByVal Value As String) lMapRed = Value End Set End Property '指定条件,分颜色显示的列名 Public WriteOnly Property BqConditionaColor()Property BqConditionaColor() As Drawing.Color Set(ByVal Value As Drawing.Color) lredColor = Value End Set End Property '指定条件,设置颜色 Public Shared Property BqColorFootBack()Property BqColorFootBack() As Brush Get Return lColorFootBack End Get Set(ByVal Value As Brush) lColorFootBack = Value End Set End Property '求和栏 脚注 背景色 Public Shared Property BqColorFootFont()Property BqColorFootFont() As Brush Get Return lColorFootFore End Get Set(ByVal Value As Brush) lColorFootFore = Value End Set End Property '求和栏 脚注 字体色#End Region初始化结束后,可以调用的属性、方法、事件、函数#Region " 初始化结束后,可以调用的属性、方法、事件、函数" Public WriteOnly Property BqSetSource()Property BqSetSource() As DataTable Set(ByVal Value As DataTable) If IsNothing(Value) Then Exit Property MyDataTable = Nothing MyDataView = Nothing MyDataTable = Value MyDataView = MyDataTable.DefaultView MyDataView.RowFilter = "" Call Mini() End Set End Property Public WriteOnly Property BqpShowNumber()Property BqpShowNumber() As Boolean Set(ByVal Value As Boolean) lshowNumber = Value If Value = True Then '显示行号 MsRowHeadr() Else Dim i As Integer For i = 0 To Me.VisibleRowCount - 1 Me.CreateGraphics.DrawString("", Me.Font, New System.Drawing.SolidBrush(Me.ForeColor), 12, i) '12是x坐标,目的是需要留下左边当前记录标志(三角形)的位置 Next Call MsRowHeaderWidth(15) Me.Refresh() End If End Set End Property '显示行号 表格显示左侧编号 Public WriteOnly Property BqpShowNull()Property BqpShowNull() As Boolean '//不显示NULL Set(ByVal Value As Boolean) Dim c As DataGridColumnStyle Dim t As DataGridTableStyle For Each t In Me.TableStyles For Each c In t.GridColumnStyles If Value Then c.NullText = "" Else c.NullText = "(null)" End If Next Next End Set End Property '不显示NULL Public WriteOnly Property BqpShowTime()Property BqpShowTime() As Boolean '//如果是日期类型,显示时间 Set(ByVal Value As Boolean) Dim c As DataGridColumnStyle Dim t As DataGridTableStyle For Each t In Me.TableStyles For Each c In t.GridColumnStyles If Not c.MappingName = "" AndAlso MyDataTable.Columns(c.MappingName).DataType.Name.IndexOf("Date") <> -1 Then If Value Then CType(c, DataGridTextBoxColumn).Format = "yyyy-MM-dd hh:mm:ss " Else CType(c, DataGridTextBoxColumn).Format = "yyyy-MM-dd " End If End If Next Next End Set End Property '如果是日期类型,显示时间 Public WriteOnly Property BqpshowAutoWidths()Property BqpshowAutoWidths() As Boolean Set(ByVal Value As Boolean) Dim c As DataGridColumnStyle Dim t As DataGridTableStyle Dim n As Integer = 0 Debug.WriteLine("BqpshowAutoWidths 共自定义有N个列 ") For Each t In Me.TableStyles n = 0 For Each c In t.GridColumnStyles c.Width = IIf(Value, bColumn(n).WidthiAutoI, bColumn(n).WidthI) Debug.WriteLine(c.MappingName + " " + bColumn(n).MapS) n = n + 1 Next Next Debug.WriteLine("BqpshowAutoWidths 共自定义有N个列 " + n.ToString) End Set End Property '是否自动显示列宽 Public WriteOnly Property BqpshowRedConditiona()Property BqpshowRedConditiona() As Boolean '是否根据条件显示 Set(ByVal Value As Boolean) lshowRedConditiona = Value Call MsShowRed() End Set End Property '指定条件,是否需要分颜色显示 Public WriteOnly Property BqpshowAllColumnS()Property BqpshowAllColumnS() As Boolean Set(ByVal Value As Boolean) lAllColumns = Value End Set End Property '是否整行选中 Public Function BqsetSum()Function BqsetSum(ByVal sField As String, ByVal lType_Avg_Count_Max_Min_Sum As String) As String Dim m0, tj, js, s As String Dim i, n As Integer i = -1 n = MFindField(sField) If n > -1 Then For n = lnewCols To bColumn.Length - 1 If UCase(sField) = UCase(bColumn(n).MapS) Then i = n Exit For End If Next End If If i >= 0 Then '在表中找到这个字段,并且在显示中也找到这个字段 Dim k As String = Trim(UCase(lType_Avg_Count_Max_Min_Sum)) Select Case Trim(UCase(k)) Case "AVG" '列平均值 s = "Avg(" Case "COUNT" '列值的计数 s = "Count(" Case "MAX" '列中最大值 ,可针对文本 s = "Max(" Case "MIN" '列中最小值 s = "Min(" Case "SUM" '列值的合计 s = "Sum(" Case Else s = "Sum(" End Select Try 'MyDataTable.Columns(bADDsm).ReadOnly = False MyNewDataRow.ItemArray = lNewRow 'MyDataTable.Columns(bADDsm).ReadOnly = True Dim lCell As DataGridCell = New DataGridCell lCell.RowNumber = MyDataTable.Rows.Count - 1 tj = bADDsm + " is null" js = s + bColumn(i).MapS + ")" m0 = MyDataTable.Compute(js, tj).ToString lCell.ColumnNumber = n Me(lCell) = m0 Catch ex As Exception End Try End If Return m0 End Function Public WriteOnly Property BqpSetSumS()Property BqpSetSumS() As String Set(ByVal Value As String) Try 'MyDataTable.Columns(bADDsm).ReadOnly = False MyNewDataRow.ItemArray = lNewRow 'MyDataTable.Columns(bADDsm).ReadOnly = True Dim lc(), ls(), ls2() As String Dim i, n As Integer lc = MgSplit(Value) If Not IsNothing(lc) Then For i = 0 To lc.Length - 1 ls = lc(i).Split("-") If Not IsNothing(ls) Then Try BqsetSum(ls(0), ls(1)) Catch ex As Exception End Try End If Next End If Catch ex As Exception End Try End Set End Property Public Property BqpTooltip()Property BqpTooltip() As String Get Return lTooltip End Get Set(ByVal Value As String) lTooltip = Value Me.oTooltip.SetToolTip(Me, Value) End Set End Property '指定提示信息 Public Event BqMSelectGrid() '外部设置,选择表格行后 Public ReadOnly Property BqpRowsCount()Property BqpRowsCount() As Integer Get Return RowCount - 1 '返回记录数,因为不需要新加的那个脚注行 End Get End Property#End Region内部定义的变量、函数、过程#Region " 内部定义的变量、函数、过程" Private Structure sBqColumnStructure sBqColumn '定义一个全局结构,每一列的相关的信息 Dim MapS As String '字段名 Dim HeaderS As String '汉字标题 Dim WidthI As Integer '宽度 像素 Dim ReadOnlyB As Boolean '是否只读 Dim RedB As Boolean '是否红字 Dim WidthiAutoI As Integer '自动时的宽度 Dim TypeS As String '数据类型, '为建立列样式的方便,只设置“Boolean,DateTime,Integer,Decimal,String”五种 '因为: Boolean 逻辑型,需要用复选框类的列样式 'DateTime日期时间型 是日期格式 'Int32 长整型、Int16整型,Byte字节型 的格式不需要小数位数 'Decimal 小数、货币、单双精 需要设置小数倍数 '其它的都是String,不需要设置格式 End Structure Dim lColumnMap As String '只是在设置属性是用此变量 需要显示的列 字段名 Dim lColumnHeader As String '只是在设置属性是用此变量 需要显示的列 汉字名 Dim lColumnWidth As String '只是在设置属性是用此变量 需要显示的列 宽度 Dim lMapOnly As String Dim lMapRed As String '只是在设置属性是用此变量 ' 分颜色显示的列名 Dim lredConditiona As String = "" Dim lredColor As Drawing.Color Dim RowCount As Integer = 0 Dim ColCount As Integer = 0 Dim SortedColNum As Integer Dim lynAscending As Boolean = False '当前排序的方式:true升序 Dim CellValueChanged As Boolean = False '是否改变当前单元格的值 Dim MyDataView As DataView Dim MyNewDataRow As DataRow Dim WithEvents MyDataTable As DataTable '带事件的对象 Dim CurrentDataGridCellLocation As DataGridCell = New DataGridCell Shared lColorFootBack As Brush Shared lColorFootFore As Brush Dim lFirst As Boolean = True Dim bColumn() As sBqColumn Dim lnewCols As Integer = 3 '新增字段的个数,显示列的起始号 Dim bADDid As String = "lAddC4321id" '新增的每行的ID,即 编号 字段的名称 Dim bADDtj As String = "lAddC1234tj" '新增的每行的TJ,即 条件 字段的名称,保存该记录是否满足条件 Dim bADDsm As String = "lAddC4444sm" '新增的每行的sm,即 求和的列 Dim oMenu As New ContextMenu '一个右键菜单 Dim sMenu() As String Dim lNewRow As Array Dim lTooltip As String Dim oTooltip As New ToolTip Dim lYnWidthAuto As Boolean '是否强制自动列宽 Dim lshowNumber As Boolean '是否显示列号 Dim lAllColumns As Boolean '是否整行选中 Dim lshowRedConditiona As Boolean '是否根据条件显示 Dim lsumlist As String Private Sub Mini()Sub Mini() 'Dim dlast As Long = System.Environment.TickCount() 'Dim ttt As Long = System.Math.Abs(System.Environment.TickCount - dlast) 'Debug.WriteLine("开始时间 " + dlast.ToString) 'Debug.WriteLine("开始时间 间隔: " + ttt.ToString) Me.DataSource = MyDataView 'ttt = System.Math.Abs(System.Environment.TickCount - dlast) 'Debug.WriteLine("1 间隔: " + ttt.ToString) Call Me.Ma1ColuArray() 'ttt = System.Math.Abs(System.Environment.TickCount - dlast) 'Debug.WriteLine("2 间隔: " + ttt.ToString) Call Me.Ma2AddColumn() ' 添加列的工作只能做一次 'End If 'ttt = System.Math.Abs(System.Environment.TickCount - dlast) 'Debug.WriteLine("3 间隔: " + ttt.ToString) ColCount = MyDataTable.Columns.Count RowCount = MyDataTable.Rows.Count Call Ma3setHead() 'ttt = System.Math.Abs(System.Environment.TickCount - dlast) 'Debug.WriteLine("4 间隔: " + ttt.ToString) Call MsRowHeaderWidth(15) 'ttt = System.Math.Abs(System.Environment.TickCount - dlast) 'Debug.WriteLine("5 间隔: " + ttt.ToString) Call Ma4Menu() 'ttt = System.Math.Abs(System.Environment.TickCount - dlast) 'Debug.WriteLine("6 间隔: " + ttt.ToString) 'Call Ma5setSum("") 'ttt = System.Math.Abs(System.Environment.TickCount - dlast) 'Debug.WriteLine("7 间隔: " + ttt.ToString) BqpShowNull = True '不显示空值 BqpShowTime = True Me.DataSource = MyDataView MyDataView.ApplyDefaultSort = False MyDataView.AllowNew = False lBM = BindingContext(MyDataView) 'Me.Select(RowCount - 1) 'ttt = System.Math.Abs(System.Environment.TickCount - dlast) 'Debug.WriteLine("8 间隔: " + ttt.ToString) 'ttt = System.Environment.TickCount 'Debug.WriteLine("结束时间: " + ttt.ToString) End Sub Private Sub Ma1ColuArray()Sub Ma1ColuArray() '初始化每个字段数组,使得需要显示的字段的格式数据化 '根据外部定义的属性来读取正确的数组初值 Dim n, i, k As Integer Dim s As String Dim nLeng As Integer nLeng = MyDataTable.Columns.Count - 1 '此时表示 表的字段数 Try Dim lc(), lcw(), lch() As String lc = MgSplit(lColumnMap) If Not IsNothing(lc) Then For i = 0 To lc.Length - 1 '去除重复的字段名称,目的的下面计算字段数是比较准确 s = Trim(UCase(lc(i))) For n = i + 1 To lc.Length - 1 If s.Length > 0 And s = Trim(UCase(lc(n))) Then ' 如果字段名非空,并且与后面的都不相同 lc(n) = " " End If Next Next Else s = "" For i = 0 To nLeng s = s + MyDataTable.Columns(i).ColumnName + "," Next lColumnMap = s lc = Nothing lc = MgSplit(lColumnMap) End If k = -1 For i = 0 To lc.Length - 1 '计算字段名数组中,在数据源中的字段数(可能有部分名称没在数据源中) If MFindField(Trim(lc(i))) >= 0 Then k = IIf(lc(i) = bADDid Or lc(i) = bADDtj, k, k + 1) '不计新加的字段 End If Next If k = -1 Then '所给的字段全部不存在,则显示所有的字段 s = "" For i = 0 To nLeng s = s + MyDataTable.Columns(i).ColumnName + "," Next lColumnMap = s Else nLeng = k '得到字段的个数,不包括新加的字段 End If 'nLeng '此时表示,有效的字段数,即包括在数据源中的字段数 ReDim bColumn(nLeng + lnewCols) k = nLeng + lc.Length + 100 ReDim lcw(k), lch(k) '需要多定义一些才行,方便与字段名对应,如果字段名不可用,则汉字名和宽度也不用 '先取出宽度和汉字标题,新增的三个字段不显示 For i = 0 To k lcw(i) = "40" lch(i) = " " Next lc = Nothing '依次取宽度 lc = MgSplit(lColumnWidth) If Not IsNothing(lc) Then k = Math.Min(lc.Length, lcw.Length) - 1 For i = 0 To k lcw(i) = lc(i) Next End If lc = Nothing '依次取汉字标题 lc = MgSplit(lColumnHeader) If Not IsNothing(lc) Then k = Math.Min(lc.Length, lch.Length) - 1 For i = 0 To k lch(i) = lc(i) Next End If For i = 0 To nLeng + lnewCols '先给初值 With bColumn(i) .MapS = IIf(i = 0, bADDsm, IIf(i = 1, bADDid, IIf(i = 2, bADDtj, Nothing))) .ReadOnlyB = True .RedB = False .WidthiAutoI = 0 .WidthI = 0 .HeaderS = IIf(i < lnewCols, "-", " ") .TypeS = IIf(i = 0, "Boolean", IIf(i = 1, "Integer", IIf(i = 2, "Boolean", Nothing))) End With Next lc = Nothing lc = MgSplit(lColumnMap) '此时,lColumnMap肯定有值了 k = -1 ''字段名、宽度、显示名这三个数组中,元素的个数,都以字段名的个数为准 For i = 0 To lc.Length - 1 '计算字段名数组中,在数据源中的字段数(可能有部分名称没在数据源中) '去除重复的字段名称 s = Trim(UCase(lc(i))) For n = i + 1 To lc.Length - 1 If s.Length > 0 And s = Trim(UCase(lc(n))) Then ' 如果字段名非空,并且与后面的都不相同 lc(n) = " " End If Next If MFindField(Trim(lc(i))) >= 0 Then If lc(i) = bADDid Or lc(i) = bADDtj Then '不计新加的字段 Else k = k + 1 bColumn(k + lnewCols).MapS = lc(i) bColumn(k + lnewCols).WidthI = CType(Val(lcw(i)), Integer) bColumn(k + lnewCols).HeaderS = lch(i) If k > nLeng Then Exit For End If End If End If Next For i = lnewCols To nLeng + lnewCols k = bColumn(i).WidthI '如果有些宽度为负,或者没有赋值,则都将宽度设置为0 bColumn(i).WidthI = IIf(k < 0, 0, IIf(k > 400, 400, k)) s = bColumn(i).HeaderS bColumn(i).HeaderS = IIf(s.Length < 1, " ", s) Next nLeng = nLeng + lnewCols lc = Nothing '红色显示的字段名 lc = MgSplit(lMapRed) If Not IsNothing(lc) Then k = lc.Length - 1 k = Math.Min(k, nLeng) For i = 0 To k '根据需要设置的红色字段的名称,在各列中查找, For n = 2 To nLeng '如果找到,则把其值设置为 True If bColumn(n).MapS = lc(i) Then bColumn(n).RedB = True Exit For End If Next Next Else '如果 红色字段名没有定义,则把所有的字段设置为 True For n = lnewCols To nLeng bColumn(n).RedB = True Next End If lc = Nothing '只读字段名 lc = MgSplit(lMapOnly) If Not IsNothing(lc) Then k = lc.Length - 1 For i = 0 To k '在各列中查找, For n = lnewCols To nLeng '如果找到,则把其值设置为 True If bColumn(n).MapS = lc(i) Then bColumn(n).ReadOnlyB = False Exit For End If Next Next End If Dim g As Graphics = Me.CreateGraphics '计算每一列自动的宽度 For i = lnewCols To nLeng '记录数据源中,某字段中最多的字符数 s = bColumn(i).MapS n = bColumn(i).HeaderS.Length '字段的标题,的字符数也参与比较 For Each r As DataRow In MyDataTable.Rows If Not IsDBNull(r(s)) Then n = Math.Max(n, Len(r(s).ToString)) End If Next n = IIf(n > 100, 100, n) '多于100个字符的,也只显示前100个字符,列宽了也不好看 'k = CInt(g.MeasureString(s, Me.Font).ToSize.Width) + 15 k = g.MeasureString(New String(CType("A", Char), n), Me.Font).Width + 15 bColumn(i).WidthiAutoI = IIf(bColumn(i).WidthI <= 0, 0, k) Next Dim ldc As DataColumn Dim m As String '计算每列的数据类型,为方便计,只分五类 For i = lnewCols To nLeng s = bColumn(i).MapS m = UCase(MyDataTable.Columns(s).DataType.ToString) Select Case m Case UCase("System.Boolean") m = "Boolean" Case UCase("System.DateTime") m = "DateTime" Case UCase("System.Int16"), UCase("System.Int32"), UCase("System.Int64"), UCase("System.Byte") m = "Integer" Case UCase("System.Decimal"), UCase("System.Single"), UCase("System.Double") m = "Decimal" Case Else m = "String" End Select bColumn(i).TypeS = m Next Catch ex As Exception End Try End Sub '初始化列数组 Private Sub Ma2AddColumn()Sub Ma2AddColumn() '加入两个新字段 Try Dim lm1 As New DataColumn Dim lm2 As New DataColumn Dim lm3 As New DataColumn With lm1 ' 我们会在自定义的排序操作期间使用此字段。 .ColumnName = bADDsm '为方便求和后排序而加的一列 .DataType = System.Type.GetType("System.Boolean") .DefaultValue = Nothing .ColumnMapping = System.Data.MappingType.Hidden End With With lm2 .ColumnName = bADDid '内部编号列 .DataType = GetType(Integer) .AllowDBNull = True End With With lm3 .ColumnName = bADDtj '是否满足条件列 .DataType = GetType(System.Boolean) .DefaultValue = False .AllowDBNull = False End With Try MyDataTable.Columns.Add(lm1) MyDataTable.Columns.Add(lm2) MyDataTable.Columns.Add(lm3) 'Call MaEditrow() '把两个字段的初值设置好...初始化时就不计算了,太慢,以后需要时才算 With lm2 .AutoIncrement = True .AutoIncrementSeed = MyDataTable.Rows.Count + 100 .AutoIncrementStep = 1 End With ' 替 DataTable 对象建立一笔注脚资料列。可以不必写入新记录的值 ' 仍然需要写新记录的值,因为,实际表的结构是有要求的。 Catch ex As Exception End Try MyDataTable.DataSet.EnforceConstraints = False 'MyDataTable.DataSet.f() MyNewDataRow = MyDataTable.NewRow() 'lm1.ReadOnly = False MyNewDataRow(bADDsm) = False 'lm1.ReadOnly = True MyDataTable.Rows.Add(MyNewDataRow) lNewRow = MyNewDataRow.ItemArray Catch ex As Exception End Try End Sub '新字段:内部编号列,是否满足条件列 Private Sub Ma3setHead()Sub Ma3setHead() Dim n, i, m As Integer '返回各个数组中最小的下标 Dim t As String Dim fTS As New System.Windows.Forms.DataGridTableStyle Dim fAbool As BqUgrdColumnBool Dim fAtext As BqUgrdColumnText Try fTS.GridColumnStyles.Clear() fTS.MappingName = MyDataTable.TableName fTS.AllowSorting = False '这一句千万不能少,这样才能控制排序时不包括脚注行,即合计行 n = bColumn.Length - 1 '需要显示的字段个数 For i = 0 To n '新增加的列不显示 t = bColumn(i).TypeS If t = "Boolean" Then fAbool = New BqUgrdColumnBool(i) AddHandler fAbool.BqmHandler, New bqeCellEventHandler(AddressOf SetEnableValues) With fAbool .HeaderText = bColumn(i).HeaderS .MappingName = bColumn(i).MapS .ReadOnly = bColumn(i).ReadOnlyB .Width = bColumn(i).WidthI .Alignment = HorizontalAlignment.Center '逻辑,居中 End With fTS.GridColumnStyles.Add(fAbool) Else fAtext = New BqUgrdColumnText(i) '重绘所有的列 AddHandler fAtext.BqmHandler, New bqeCellEventHandler(AddressOf SetEnableValues) With fAtext .HeaderText = bColumn(i).HeaderS .MappingName = bColumn(i).MapS .ReadOnly = bColumn(i).ReadOnlyB .Width = bColumn(i).WidthI If t = "DateTime" Then '时间,左对齐 .TextBox.TextAlign = HorizontalAlignment.Left .Alignment = HorizontalAlignment.Left .Format = "yyyy-MM-dd hh:mm:ss" ElseIf t = "Integer" Then '数字,整数 .TextBox.TextAlign = HorizontalAlignment.Right .Alignment = HorizontalAlignment.Right .Format = "###,###,###,###,###" '最好是不显示0或空值 ElseIf t = "Decimal" Then '数字,小数 .TextBox.TextAlign = HorizontalAlignment.Right .Alignment = HorizontalAlignment.Right .Format = "###,###,###,###,###,###.0000" Else '其它文本 .TextBox.TextAlign = HorizontalAlignment.Left .Alignment = HorizontalAlignment.Left End If End With fTS.GridColumnStyles.Add(fAtext) End If If i < 3 Then fTS.PreferredColumnWidth = 0 MyDataTable.Columns(bColumn(i).MapS).ColumnMapping = MappingType.Hidden End If Next With Me .TableStyles.Clear() .TableStyles.Add(fTS) .AllowSorting = False ' 停用 DataGrid 控制项的默认排序功能。 .CaptionVisible = IIf(MyDataTable.DataSet.Relations.Count > 0, True, False) '如果有关联,则显示标题 End With Call MsRowHeaderWidth(15) Catch ex As Exception Dim kk As String kk = "" End Try End Sub '显示中文标题 Private Sub Ma4Menu()Sub Ma4Menu() ReDim sMenu(12) sMenu(0) = "自动列宽" sMenu(1) = "显示行编号" sMenu(2) = "不显示Null" sMenu(3) = "显示时间" sMenu(4) = "整行选中" sMenu(5) = "红字条件" sMenu(6) = "统计与计算" sMenu(7) = "合计" sMenu(8) = "平均值" sMenu(9) = "计数" sMenu(10) = "最大值" sMenu(11) = "最小值" sMenu(12) = "-清除-统计内容" Dim i As Integer Dim m6 As MenuItem oMenu.MenuItems.Clear() For i = 0 To sMenu.Length - 1 Dim mi As New MenuItem mi.Text = sMenu(i) mi.Checked = False mi.Enabled = True AddHandler mi.Click, AddressOf mMenuClick '定义各个菜单的click事件 If i > 6 And i <= 12 Then m6.MenuItems.Add(mi) Else oMenu.MenuItems.Add(mi) End If If i = 5 Then '第五个菜单,并且没有设置条件表达式,则不可选择 If lredConditiona.Length < 2 Then mi.Enabled = False End If End If If i = 6 Then m6 = mi End If Next Me.ContextMenu = oMenu End Sub '定义菜单 Private Sub mMenuClick()Sub mMenuClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Dim s As String Dim i As Boolean Try s = sender.text i = IIf(sender.checked = True, True, False) i = Not i If s = sMenu(7) Or s = sMenu(8) Or s = sMenu(8) Or s = sMenu(9) Or s = sMenu(10) Or s = sMenu(11) Or s = sMenu(12) Then Dim lm As MenuItem = sender For Each lm In lm.Parent.MenuItems lm.Checked = False Next 'sender.checked = False End If Select Case s Case sMenu(0) 'i = Not i Me.BqpshowAutoWidths = i Case sMenu(1) 'i = Not i Me.BqpShowNumber = i Case sMenu(2) 'i = Not i Me.BqpShowNull = i Case sMenu(3) 'i = Not i Me.BqpShowTime = i Case sMenu(4) 'i = Not i Me.BqpshowAllColumnS = i Case sMenu(5) 'i = Not i Me.BqpshowRedConditiona = i Case sMenu(7) Me.Ma5setSum("Sum") Case sMenu(8) Me.Ma5setSum("avg") Case sMenu(9) Me.Ma5setSum("count") Case sMenu(10) Me.Ma5setSum("max") Case sMenu(11) Me.Ma5setSum("min") Case sMenu(12) Try 'MyDataTable.Columns(bADDsm).ReadOnly = False MyNewDataRow.ItemArray = lNewRow 'MyDataTable.Columns(bADDsm).ReadOnly = True Catch ex As Exception End Try End Select sender.checked = i Catch ex As Exception End Try End Sub Private Sub Ma5setSum()Sub Ma5setSum(ByVal lType_Avg_Count_Max_Min_Sum As String) Dim s, tj, js As String '聚和函数、条件、计算字段 Dim i, n As Integer Dim m0 As String '每一次计算的结果 Dim k As String = Trim(UCase(lType_Avg_Count_Max_Min_Sum)) Select Case Trim(UCase(k)) Case "AVG" '列平均值 s = "Avg(" Case "COUNT" '列值的计数 s = "Count(" Case "MAX" '列中最大值 ,可针对文本 s = "Max(" Case "MIN" '列中最小值 s = "Min(" Case "SUM" '列值的合计 s = "Sum(" Case Else s = "Sum(" End Select Try 'MyDataTable.Columns(bADDsm).ReadOnly = False MyNewDataRow.ItemArray = lNewRow 'MyDataTable.Columns(bADDsm).ReadOnly = True Dim lCell As DataGridCell = New DataGridCell lCell.RowNumber = MyDataTable.Rows.Count - 1 tj = bADDsm + " is null" n = bColumn.Length - 1 For i = lnewCols To n If k = "MAX" Or k = "MIN" Then '最大值,最小值,对所有的字段都求 Try m0 = "" js = s + bColumn(i).MapS + ")" m0 = MyDataTable.Compute(js, tj).ToString lCell.ColumnNumber = i Me(lCell) = m0 Catch ex As Exception End Try Else If (bColumn(i).TypeS = "Integer" Or bColumn(i).TypeS = "Decimal") Then '对所有数值型数据 Try m0 = "" js = s + bColumn(i).MapS + ")" m0 = MyDataTable.Compute(js, tj).ToString lCell.ColumnNumber = i Me(lCell) = m0 Catch ex As Exception End Try End If End If Next Catch ex As Exception '遇到错误,从下一个开始继续 End Try End Sub '设定注脚储存格的值。 Private Function MFindField()Function MFindField(ByVal sField As String) As Integer '判断sField字段是否在表中,在则返回 -1 Dim i, m As Integer m = -1 For i = 0 To MyDataTable.Columns.Count - 1 If UCase(sField) = UCase(MyDataTable.Columns(i).ColumnName) Then m = i Exit For End If Next MFindField = m End Function Private Function MgSplit()Function MgSplit(ByVal s As String) As String() '从指字符串中分离各个子串 ,分隔符用逗号 '参数:字符串, Dim m0 As String() = Nothing Dim m As String Try If Trim(s).Length > 0 Then m = s.Replace(",", "") '除去逗号,以防止s全部都是逗号这种情况 If m.Length > 0 Then m0 = s.Split(",") End If End If Catch ex As Exception End Try Return m0 End Function '从指字符串中分离各个子串 Private Function MsRowHeaderWidth()Function MsRowHeaderWidth(ByVal Width As Integer) If Me.TableStyles.Count = 0 Then Me.RowHeaderWidth = Width Else Me.TableStyles(0).RowHeaderWidth = Width End If End Function '设置行标题的宽度 Private Sub MaEditrow()Sub MaEditrow() Dim r As DataRow Dim i As Integer = 0 Try '预防条件表达式设置不正确, 'If MFindField(bADDid) >= 0 Then For Each r In MyDataTable.Rows r(bADDid) = i i = i + 1 Next 'End If 'If MFindField(bADDtj) >= 0 Then If lredConditiona.Length > 1 Then '如果条件已经设置,则把满足条件的记录找出来 Dim rs() As DataRow rs = MyDataTable.Select(lredConditiona) '找到满足条件的记录 For Each r In rs r(bADDtj) = True 's2代表满足条件 列名 Next End If 'End If Catch ex As Exception End Try End Sub Private Sub MsRowHeadr()Sub MsRowHeadr() Dim g As System.Drawing.Graphics 'Dim iCount As Integer Dim i, r, r1, r2, t, w As Integer Dim m As String Try g = Me.CreateGraphics i = MyDataView.Count t = Me.GetCellBounds(0, 0).Top r = CInt(t / ((Me.GetCellBounds(RowCount - 1, 0).Top - t + Me.GetCellBounds(0, 0).Height) / RowCount)) r = r - CInt(IIf(False, 1, IIf(Me.CaptionVisible = True, 2, 1))) r1 = IIf(r < 0, -r, 0) '上面几行:得到可显示区域 第一行的行号 r = Me.VisibleRowCount r = r1 + r r2 = IIf(r < i, r, i) '得到可显示区域 最后一行的行号 w = CInt(g.MeasureString(r2.ToString, Me.Font).Width) + 15 '设置行标题的列宽 MsRowHeaderWidth(w) w = r2.ToString.Length For i = r1 To r2 - 1 t = Me.GetCellBounds(i, 0).Top + 2 m = "" & Trim(CStr(i + 1)) '留前置空格 m = IIf(m.Length = w, m, Space(w - m.Length) + m) If i = RowCount - 1 Then m = "汇总" g.DrawString(m, Me.Font, New System.Drawing.SolidBrush(Me.ForeColor), 6, t) Else g.DrawString(m, Me.Font, New System.Drawing.SolidBrush(Me.ForeColor), 12, t) End If '12是x坐标,目的是需要留下左边当前记录标志(三角形)的位置 Next Catch ex As Exception Dim kk As String kk = "" End Try End Sub '以下代码是在表格中最左边显示行号 Private Sub MsShowRed()Sub MsShowRed() If lredConditiona.Length < 2 Then Exit Sub '如果没有设置条件,则不用设置 If lshowRedConditiona = True Then '需要分颜色显示满足条件的记录 Dim c As DataGridColumnStyle Dim t As DataGridTableStyle Dim i As Integer Else End If End Sub#End Region Dim WithEvents lBM As System.Windows.Forms.BindingManagerBase控件自身的事件和方法#Region " 控件自身的事件和方法 " ' 处理 DataTable 对象的 ColumnChanged 事件, ' 以便当储存格中的资料有所变动时能够加以追踪。 Private Sub MyDataTable_ColumnChanged()Sub MyDataTable_ColumnChanged(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs) Handles MyDataTable.ColumnChanged Dim Row As Integer, Col As Integer Row = 0 Col = 0 ' 判断哪一个资料列内含资料变更的储存格。 Dim r As DataRow For Each r In MyDataTable.Rows If (r.Equals(e.Row)) Then CurrentDataGridCellLocation.RowNumber = Row CellValueChanged = True Exit For Row = Row + 1 End If Next ' 判断哪一个资料行内含资料变更的储存格。 Dim lc As DataColumn For Each lc In MyDataTable.Columns If (lc.Equals(e.Column)) Then CurrentDataGridCellLocation.ColumnNumber = Col CellValueChanged = True Exit For Col = Col + 1 End If Next End Sub ' 处理 DataGrid 控制项的 CurrentCellChanged 事件。 Private Sub BqUDataGrid_CurrentCellChanged()Sub BqUDataGrid_CurrentCellChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.CurrentCellChanged If (CellValueChanged = True) Then '---------------------需要再改一下,使得修改值后仍然回到原单元格 Call Ma5setSum("") End If CellValueChanged = False RaiseEvent BqMSelectGrid() '调用自定义过程,让控件外部可以根据表格选择内容变化而变化 End Sub ' 处理 DataGrid 控制项的 MouseDown 事件以便实现自定义排序。 Private Sub BqUDataGrid_MouseDown()Sub BqUDataGrid_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown ''还需要设置,不想让最后一行得到焦点 '''Dim myHitTest As DataGrid.HitTestInfo '''myHitTest = Me.HitTest(e.X, e.Y) '''Debug.WriteLine("Column " & myHitTest.Column) '''Debug.WriteLine("Row " & myHitTest.Row) '''Debug.WriteLine("Type " & myHitTest.Type) '''Debug.WriteLine("ToString " & myHitTest.ToString) '''Debug.WriteLine("Format " & myHitTest.Type.ToString) '''Debug.WriteLine(RowCount.ToString) '''If myHitTest.Type = DataGrid.HitTestType.Cell Then ''' Dim k1, k2 As Integer ''' k1 = myHitTest.Row ''' k2 = myHitTest.Column ''' If k1 = RowCount - 1 Then ''' Me.CurrentRowIndex = k1 - 1 ''' End If ''' 'Dim ee As New bqeCellEventArgs(k1, k2) ' 使用作用资料列与作用资料行的编号来初始化事件指针。 ''' 'RaiseEvent BqmHandler(Me, ee) ' 引发 bqmHandler 事件。 ''' 'If Not ee.EnableValue Then ' 设定注脚资料列的前景色与背景色。 ''' ' Me.CurrentRowIndex = k1 - 1 ''' 'End If '''End If Dim lInfo As DataGrid.HitTestInfo Dim m As String lInfo = Me.HitTest(e.X, e.Y) ' 判断用户是否单击资料行标题。 If (lInfo.Type = DataGrid.HitTestType.ColumnHeader) And e.Button = MouseButtons.Left Then '只有左键才设置 Dim n As Integer = lInfo.Column If (n <> -1) Then ' 执行自定义排序。要完成此项操作,请固定以递增顺序来排序 Boolean▲△▼▽∧∨↑↓↖↗↘↙ ' 资料型别字段,如此一来,注脚资料列才会显示在最下方。 Dim MyChar() As Char = {"▲"c, "▽"c} 'SortedColNum 表示上一次排序的位置, With Me.TableStyles(0).GridColumnStyles(SortedColNum) m = .HeaderText.Trim(MyChar).Trim() '要清除其上面的排序标志 .HeaderText = m End With m = bColumn(n).MapS With Me.TableStyles(0).GridColumnStyles(n) If (lynAscending = True) Then MyDataView.Sort = bADDsm + " Asc," + m + " desc" .HeaderText = "▲" + bColumn(n).HeaderS Else MyDataView.Sort = bADDsm + " Asc," + m + " asc" .HeaderText = "▽" + bColumn(n).HeaderS End If lynAscending = Not lynAscending SortedColNum = n End With End If End If End Sub ' 停用 DataGrid 控制项的注脚资料列。 Public Sub SetEnableValues()Sub SetEnableValues(ByVal sender As Object, ByVal e As bqeCellEventArgs) If (e.Row = RowCount - 1) Then '表示最后一行,即脚注行 e.EnableValue = False Else e.EnableValue = True End If End Sub ' 完成整行选中状态的设置 Public Event BqmHandler As bqeCellEventHandler Private Sub BqUDataGrid_MouseMove()Sub BqUDataGrid_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove If Me.CurrentRowIndex < 0 Then Exit Sub If lAllColumns Then Dim lhit As DataGrid.HitTestInfo Dim t As DataGridTableStyle For Each t In Me.TableStyles t.SelectionBackColor = Me.SelectionBackColor t.SelectionForeColor = Me.SelectionForeColor t.ForeColor = Me.ForeColor t.GridLineColor = Me.GridLineColor Next lhit = Me.HitTest(e.X, e.Y) If lhit.Row <> -1 OrElse lhit.Column <> -1 Then Me.Select(Me.CurrentRowIndex) End If End If End Sub Private Sub BqUDataGrid_Paint()Sub BqUDataGrid_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint If lshowNumber = True Then MsRowHeadr() End If End Sub#End Region还需要完善的功能 写完后,复制到上面类中#Region "还需要完善的功能 写完后,复制到上面类中" Public ReadOnly Property BqpKeyTag()Property BqpKeyTag(ByVal FieldName As String) As String Get Dim m0 As String = "-1" Dim i As Integer Try i = MFindField(FieldName) If i >= 0 Then Dim rv As DataRowView = MyDataView.Item(lBM.Position) m0 = rv.Row(FieldName).ToString End If Catch ex As Exception End Try Return m0 End Get End Property '根据字段名返回其值 Public ReadOnly Property BqpRecornTJ()Property BqpRecornTJ() As Boolean '当前记录是否满足条件 Get Dim m0 As Boolean = False Try If lFirst = True Then Call Me.MaEditrow() ' 添加列后,还需要计算其它两列的数据 lFirst = False End If Dim rv As DataRowView = MyDataView.Item(lBM.Position) m0 = rv.Row(bADDtj).ToString Catch ex As Exception End Try Return m0 End Get End Property '当前记录是否满足条件 Public ReadOnly Property BqpRConditionaRowS()Property BqpRConditionaRowS() As DataRow() Get Dim m0 As DataRow() Try If lFirst = True Then Call Me.MaEditrow() ' 添加列后,还需要计算其它两列的数据 lFirst = False End If Dim s As String s = bADDtj + " =True And " + bADDsm + " is null " m0 = MyDataTable.Select(s) Catch ex As Exception End Try Return m0 End Get End Property '满足条件的记录集 'Public Sub BqMrowAdd(ByVal r As Array) ' 'Dim l As DataRow ' 'l = lSourceTb.NewRow() ' 'Dim i As Integer ' 'l.ItemArray = r ' 'lSourceTb.Rows.Add(r) ' ''lBMtb = New System.Windows.Forms.BindingManagerBase ' ''lBMtb = BindingContext(lSourceTb) ' ''i = lBMtb.Position ' ''lBMtb = CType(Me.BindingContext(Me.DataSource), CurrencyManager) ' ''lBMtb.Position = i ' 'Me.Refresh() 'End Sub '添加记录 'Public Sub BqMrowRemove(ByVal r As DataRow) ' 'lSourceTb.Rows.Remove(r) ' Me.Refresh() 'End Sub '移出记录#End RegionEnd Class#End Region需要的其它自定义类#Region " 需要的其它自定义类"' 声明一个委派给用于停用 DataGrid 控制项之储存格的事件使用。Public Delegate Sub bqeCellEventHandler()Sub bqeCellEventHandler(ByVal sender As System.Object, ByVal e As bqeCellEventArgs)' 定义一个衍生自 EventArgs 类别的事件指针类别 以便提供资料给 bqmHandler 事件。Public Class bqeCellEventArgsClass bqeCellEventArgs Inherits System.EventArgs Dim lCol As Integer Dim lRow As Integer Dim lValue As Boolean Public Sub New()Sub New(ByVal Row As Integer, ByVal Col As Integer) lRow = Row lCol = Col lValue = True End Sub Public Property Column()Property Column() As Integer Get Return lCol End Get Set(ByVal Value As Integer) lCol = Value End Set End Property Public Property Row()Property Row() As Integer Get Return lRow End Get Set(ByVal Value As Integer) lRow = Value End Set End Property Public Property EnableValue()Property EnableValue() As Boolean Get Return lValue End Get Set(ByVal Value As Boolean) lValue = Value End Set End PropertyEnd ClassPublic Class BqUgrdColumnTextClass BqUgrdColumnText Inherits System.Windows.Forms.DataGridTextBoxColumn ' 替我们所定义的 bqeCellEventHandler 委派声明一个事件。 Public Event BqmHandler As bqeCellEventHandler Private MyCol As Integer ' 储存 BqUgrdColumnText 控制项将被添加其中之资料行的资料行编号。 Public Sub New()Sub New(ByVal Column As Integer) MyCol = Column End Sub ' 覆写 Paint 方法以便设定注脚资料列的色彩。 Protected Overloads Overrides Sub Paint()Sub Paint(ByVal g As System.Drawing.Graphics, _ ByVal bounds As System.Drawing.Rectangle, _ ByVal source As System.Windows.Forms.CurrencyManager, _ ByVal rowNum As Integer, _ ByVal backBrush As System.Drawing.Brush, _ ByVal foreBrush As System.Drawing.Brush, _ ByVal alignToRight As Boolean) Dim e As New bqeCellEventArgs(rowNum, MyCol) ' 使用作用资料列与作用资料行的编号来初始化事件指针。 RaiseEvent BqmHandler(Me, e) ' 引发 bqmHandler 事件。 If Not e.EnableValue Then ' 设定注脚资料列的前景色与背景色。 If BqUDataGrid.BqColorFootBack Is Nothing Or BqUDataGrid.BqColorFootFont Is Nothing Then backBrush = Brushes.DimGray ' Brushes.DarkSlateGray foreBrush = Brushes.LightGreen Else backBrush = BqUDataGrid.BqColorFootBack foreBrush = BqUDataGrid.BqColorFootFont End If End If ' 调用 DataGridTextBoxColumn 类别的 Paint 方法。 MyBase.Paint(g, bounds, source, rowNum, backBrush, foreBrush, alignToRight) End Sub ' 覆写 Edit 方法以便停用注脚资料列。 Protected Overloads Overrides Sub Edit()Sub Edit(ByVal source As System.Windows.Forms.CurrencyManager, _ ByVal rowNum As Integer, ByVal bounds As System.Drawing.Rectangle, ByVal readOnlyFlag As Boolean, _ ByVal instantText As String, ByVal cellIsVisible As Boolean) Dim e As bqeCellEventArgs = Nothing e = New bqeCellEventArgs(rowNum, MyCol) ' 使用作用资料列与作用资料行的编号来初始化事件指针。 RaiseEvent BqmHandler(Me, e) ' 引发 bqmHandler 事件。 ' 替除了注脚资料列以外的所有资料列调用 DataGridTextBoxColumn 类别的 Edit 方法。 If e.EnableValue Then MyBase.Edit(source, rowNum, bounds, readOnlyFlag, instantText, cellIsVisible) End If End SubEnd Class '自定义的DataGridTextBoxColumnPublic Class BqUgrdColumnBoolClass BqUgrdColumnBool Inherits System.Windows.Forms.DataGridBoolColumn ' 替我们所定义的 bqeCellEventHandler 委派声明一个事件。 Public Event BqmHandler As bqeCellEventHandler Private MyCol As Integer '' 储存 BqUgrdColumnText 控制项将被添加其中之资料行的资料行编号。 Public Sub New()Sub New(ByVal Column As Integer) MyCol = Column End Sub ' 覆写 Paint 方法以便设定注脚资料列的色彩。 Protected Overloads Overrides Sub Paint()Sub Paint(ByVal g As System.Drawing.Graphics, _ ByVal bounds As System.Drawing.Rectangle, _ ByVal source As System.Windows.Forms.CurrencyManager, _ ByVal rowNum As Integer, _ ByVal backBrush As System.Drawing.Brush, _ ByVal foreBrush As System.Drawing.Brush, _ ByVal alignToRight As Boolean) Dim e As New bqeCellEventArgs(rowNum, MyCol) ' 使用作用资料列与作用资料行的编号来初始化事件指针。 RaiseEvent BqmHandler(Me, e) ' 引发 bqmHandler 事件。 If Not e.EnableValue Then ' 设定注脚资料列的前景色与背景色。 If BqUDataGrid.BqColorFootBack Is Nothing _ Or BqUDataGrid.BqColorFootFont Is Nothing Then backBrush = Brushes.DimGray ' Brushes.DarkSlateGray foreBrush = Brushes.LightGreen Else backBrush = BqUDataGrid.BqColorFootBack foreBrush = BqUDataGrid.BqColorFootFont End If End If ' 调用 DataGridTextBoxColumn 类别的 Paint 方法。 MyBase.Paint(g, bounds, source, rowNum, backBrush, foreBrush, alignToRight) End Sub ' 覆写 Edit 方法以便停用注脚资料列。 Protected Overloads Overrides Sub Edit()Sub Edit(ByVal source As System.Windows.Forms.CurrencyManager, _ ByVal rowNum As Integer, ByVal bounds As System.Drawing.Rectangle, ByVal readOnlyFlag As Boolean, _ ByVal instantText As String, ByVal cellIsVisible As Boolean) Dim e As bqeCellEventArgs = Nothing e = New bqeCellEventArgs(rowNum, MyCol) ' 使用作用资料列与作用资料行的编号来初始化事件指针。 RaiseEvent BqmHandler(Me, e) ' 引发 bqmHandler 事件。 ' 替除了注脚资料列以外的所有资料列调用 DataGridTextBoxColumn 类别的 Edit 方法。 If e.EnableValue Then MyBase.Edit(source, rowNum, bounds, readOnlyFlag, instantText, cellIsVisible) End If End SubEnd Class '自定义的DataGridBoolColumn#End Region