I have a DGV
on a tab control, with it's parent tab not the initially visible tab (i.e. dgv on TabPage2 with TabPage1 visible).
The grids data-source is populated and assigned on form load, in Data-binding complete I'm adding new columns and assigning an event handler to their header cell click, all OK so far.
However when I change tab to make the DGV
visible data-binding complete fires for a second time, at this stage the event handler has been lost, what causes the event to fire for a second time?
What causes the Event handler to have been lost? Is there a way to work around this?
Thanks
Edit:
The cause appears to be the column is reverting to the underlying type, i.e. in DataBindingComplete I add a column DGVTextColumn which inherits from DataGridViewTextBoxColumn, the second time that DataBindingComplete fires the column is of the type DataGridViewTextBoxColumn rather than the inherited type DGVTextColumn if that helps anyone?
The important factor appears to be the column being bound, taking an empty form and adding a tab control to it, place a datagridview
in tabpage2, revert back to tabpage1 paste the code at the bottom into the forms code.
Private Sub DataGridView1_DataBindingComplete(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewBindingCompleteEventArgs) Handles DataGridView1.DataBindingComplete
If Not DataGridView1.Columns.Contains("colBool") Then
Dim col As New DGVColumn
col.Name = "colBool"
col.DataPropertyName = "Checked" 'When this is included the checkbox appears unticked, however commenting this line out means that the checkbox appears ticked upon changing to TabPage2
col.Checked = True
DataGridView1.Columns.Add(col)
End If
End Sub
Code to reproduce:
Imports System.ComponentModel
Imports System.Windows.Forms.VisualStyles
Public Class Form1
Private list As BindingList(Of iPerson)
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
list = New BindingList(Of iPerson)
list.Add(New Person(0, "Steve", "Smith"))
list.Add(New Person(1, "Gomez", "Juan"))
list.Add(New Person(1, "Jones", "Paul"))
DataGridView1.DataSource = list
End Sub
Private Sub DataGridView1_DataBindingComplete(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewBindingCompleteEventArgs) Handles DataGridView1.DataBindingComplete
If Not DataGridView1.Columns.Contains("colBool") Then
Dim col As New DGVColumn
col.Name = "colBool"
col.DataPropertyName = "Checked"
col.Checked = True
DataGridView1.Columns.Add(col)
End If
End Sub
Private Interface iPerson
ReadOnly Property Forename() As String
ReadOnly Property Surname() As String
ReadOnly Property Checked() As Boolean
End Interface
Private Class Person
Implements iPerson
Private _ID As Integer
Private _Forename As String
Private _Surname As String
Private _checked As Boolean
Public Sub New(ByVal ID As Integer, ByVal Forename As String, ByVal Surname As String)
_ID = ID
_Forename = Forename
_Surname = Surname
_checked = False
End Sub
Public ReadOnly Property Forename() As String Implements iPerson.Forename
Get
Return _Forename
End Get
End Property
Public ReadOnly Property Surname() As String Implements iPerson.Surname
Get
Return _Surname
End Get
End Property
Public ReadOnly Property Checked() As Boolean Implements iPerson.Checked
Get
Return _checked
End Get
End Property
End Class
Private Class DGVHeaderCell
Inherits DataGridViewColumnHeaderCell
Private checkBoxLocation As Point
Private checkBoxSize As Size
Private _checked As Boolean = False
Private _cellLocation As New Point()
Public Event OnCheckBoxClicked()
Public Sub New()
End Sub
Protected Overrides Function GetPreferredSize(ByVal graphics As System.Drawing.Graphics, ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, ByVal rowIndex As Integer, ByVal constraintSize As System.Drawing.Size) As System.Drawing.Size
Dim calcSize = MyBase.GetPreferredSize(graphics, cellStyle, rowIndex, constraintSize)
calcSize.Height += CheckBoxRenderer.GetGlyphSize(graphics, System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal).Height + 3
Return calcSize
End Function
Protected Overrides Sub Paint(ByVal graphics As System.Drawing.Graphics, ByVal clipBounds As System.Drawing.Rectangle, ByVal cellBounds As System.Drawing.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)
Dim p As New Point()
Dim s As Size = CheckBoxRenderer.GetGlyphSize(graphics, System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal)
p.X = CInt(cellBounds.Location.X + (cellBounds.Width / 2) - (s.Width / 2))
p.Y = cellBounds.Location.Y + cellBounds.Height - s.Height - 3
Dim rect As Rectangle = cellBounds
rect.Height -= CheckBoxRenderer.GetGlyphSize(graphics, System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal).Height
Using txtBrush As New SolidBrush(cellStyle.ForeColor)
Dim format As New StringFormat
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Center
graphics.DrawString(formattedValue.ToString, cellStyle.Font, txtBrush, rect, format)
End Using
_cellLocation = cellBounds.Location
checkBoxLocation = p
checkBoxSize = s
Dim _cbState As CheckBoxState = System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal
If _checked Then
_cbState = System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal
End If
CheckBoxRenderer.DrawCheckBox(graphics, checkBoxLocation, _cbState)
End Sub
Protected Overrides Sub OnMouseClick(ByVal e As DataGridViewCellMouseEventArgs)
Dim p As New Point(e.X + _cellLocation.X, e.Y + _cellLocation.Y)
If p.X >= checkBoxLocation.X AndAlso p.X <= checkBoxLocation.X + checkBoxSize.Width AndAlso p.Y >= checkBoxLocation.Y AndAlso p.Y <= checkBoxLocation.Y + checkBoxSize.Height Then
_checked = Not _checked
RaiseEvent OnCheckBoxClicked()
Me.DataGridView.InvalidateCell(Me)
End If
MyBase.OnMouseClick(e)
End Sub
Public Property Checked() As Boolean
Get
Return _checked
End Get
Set(ByVal value As Boolean)
_checked = value
End Set
End Property
End Class
Friend Class DGVColumn
Inherits DataGridViewTextBoxColumn
Private _headerCell As DGVHeaderCell
Public Sub New()
_headerCell = New DGVHeaderCell()
AddHandler _headerCell.OnCheckBoxClicked, AddressOf THISHANDLER
Me.HeaderCell = _headerCell
Me.Width = 50
End Sub
Private Sub THISHANDLER()
MsgBox("Clicked")
End Sub
Public Property Checked() As Boolean
Get
Return _headerCell.Checked
End Get
Set(ByVal value As Boolean)
_headerCell.Checked = value
End Set
End Property
End Class
End Class