65.9K
CodeProject 正在变化。 阅读更多。
Home

在 ComboBox 中嵌入 DataGridView

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (17投票s)

2012 年 11 月 12 日

CPOL

5分钟阅读

viewsIcon

72646

downloadIcon

3650

一种将任何 DataGridView 放入 ComboBox 的简单方法。

引言

多列组合框在 WinForms 应用程序中非常常见。然而,目前还没有开源解决方案能够完全支持数据绑定并且像 DataGridView 控件那样可定制。本文的目的是展示如何用相对少量代码轻松创建一个。

满足需求最明显、最直接、最简单的方法是将 DataGridView 托管在 ComboBox 中。这似乎是一项不简单的任务,但实际上(至少在完成之后)它非常容易实现。

本文及提供的源代码更多是“概念验证”类型,而非成品控件。有许多细节并非完全“技术性”或美观。另一方面,我在一个开源程序中使用它(DevExpress 不适用),对我来说效果很好。

这也是我第一篇编程文章,请原谅我的糟糕风格 微笑 | <img src=

AccGridComboBox control preview

背景 

本文基于以下文章中的创意

首先创建一个自定义 ToolStripControlHost,然后用它来创建一个自定义 ComboBox,再用它来创建一个 IDataGridViewEditingControl、一个自定义 DataGridViewCell 和一个自定义 DataGridViewColumn

使用代码 

使用提供的自定义 AccGridComboBoxDataGridViewAccGridComboBoxColumn 类就像使用 ComboBoxDataGridViewColumn 本身一样简单。

您只需要像添加 ComboBoxDataGridViewColumn 一样,将 AccGridComboBoxDataGridViewAccGridComboBoxColumn 添加到窗体中,并为其指定一个相应的 DataGridView 来代替数据源。

' for columns    
DataGridViewAccGridComboBoxColumn1.ComboDataGridView = ProgramaticalyCreatedDataGridView
' selection is done by single click, i.e. not double click
DataGridViewAccGridComboBoxColumn1.CloseOnSingleClick = True
' binding is trigered on value change, i.e. not on validating
DataGridViewAccGridComboBoxColumn1.InstantBinding = True

' for comboboxes (second param is CloseOnSingleClick property setter)
AccGridComboBox1.AddDataGridView(ProgramaticalyCreatedDataGridView, True)
AccGridComboBox1.InstantBinding = True

一个快速、自明的示例,演示如何以编程方式创建 DataGridView

Public Function CreateDataGridViewForPersonInfo(ByVal TargetForm As Form, _
        ByVal ListBindingSource As BindingSource) As DataGridView
 
    ' create the resulting grid and it's columns
    Dim result As New DataGridView
    Dim DataGridViewTextBoxColumn1 As New System.Windows.Forms.DataGridViewTextBoxColumn
    Dim DataGridViewTextBoxColumn2 As New System.Windows.Forms.DataGridViewTextBoxColumn

    ' begin initialization (to minimize events)
    CType(result, System.ComponentModel.ISupportInitialize).BeginInit()

    ' setup grid properties as you need
    result.AllowUserToAddRows = False
    result.AllowUserToDeleteRows = False
    result.AutoGenerateColumns = False
    result.AllowUserToResizeRows = False
    result.ColumnHeadersVisible = False
    result.RowHeadersVisible = False
    result.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells
    result.ReadOnly = True
    result.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect
    result.Size = New System.Drawing.Size(300, 220)
    result.AutoSize = False
    
    ' add datasource
    result.DataSource = ListBindingSource
    
    ' add columns
    result.Columns.AddRange(New System.Windows.Forms.DataGridViewColumn() _
        {DataGridViewTextBoxColumn1, DataGridViewTextBoxColumn2})
    
    ' setup columns as you need
    DataGridViewTextBoxColumn1.AutoSizeMode = _
         System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill
    DataGridViewTextBoxColumn1.DataPropertyName = "Name"
    DataGridViewTextBoxColumn1.HeaderText = "Name"
    DataGridViewTextBoxColumn1.Name = ""
    DataGridViewTextBoxColumn1.ReadOnly = True

    DataGridViewTextBoxColumn2.DataPropertyName = "Code"
    DataGridViewTextBoxColumn2.HeaderText = "Code"
    DataGridViewTextBoxColumn2.Name = ""
    DataGridViewTextBoxColumn2.ReadOnly = True
    DataGridViewTextBoxColumn2.AutoSizeMode = DataGridViewAutoSizeColumnMode.NotSet

    ' assign binding context of the form that hosts
    ' the control in order to enable databinding
    result.BindingContext = TargetForm.BindingContext

    ' end initialization
    CType(result, System.ComponentModel.ISupportInitialize).EndInit()
    
    Return result

End Function

关注点

创建自定义 ToolStripControlHost

控件的核心是一个名为 ToolStripDataGridView 的类,它继承自 ToolStripControlHostToolStripDataGridView 类提供了 4 个新的、自明的属性:CloseOnSingleClickDataGridViewControlMinDropDownWidthDropDownHeight。目前,我将 MinDropDownWidthDropDownHeight 属性设为只读。它们的值在构造函数中由相应的 DataGridView 属性 WidthHeight 设置,以将所有网格区域自定义代码限制在网格创建代码内部。尽管这仅仅是偏好问题。

ToolStripDataGridView 类使用 ToolStripControlHost 受保护的可覆盖子程序 OnSubscribeControlEventsOnUnsubscribeControlEvents 来订阅和取消订阅子 DataGridView 事件。

' Subscribe and unsubscribe the control events you wish to expose.
Protected Overrides Sub OnSubscribeControlEvents(ByVal c As Control)
    
    ' Call the base so the base events are connected.
    MyBase.OnSubscribeControlEvents(c)
    
    Dim nDataGridView As DataGridView = DirectCast(c, DataGridView)

    ' Add the events:
    ' to highlight the item that is currently under the mouse pointer
    AddHandler nDataGridView.CellMouseEnter, AddressOf OnDataGridViewCellMouseEnter
    ' to accept selection by enter key
    AddHandler nDataGridView.KeyDown, AddressOf OnDataGridViewKeyDown
    ' to accept selection by double clicking
    AddHandler nDataGridView.CellDoubleClick, AddressOf myDataGridView_DoubleClick
    ' to accept selection by single click (if CloseOnSingleClick is set tor TRUE)
    AddHandler nDataGridView.CellClick, AddressOf myDataGridView_Click

End Sub

Protected Overrides Sub OnUnsubscribeControlEvents(ByVal c As Control)
    
    ' Call the base method so the basic events are unsubscribed.
    MyBase.OnUnsubscribeControlEvents(c)

    Dim nDataGridView As DataGridView = DirectCast(c, DataGridView)
 
    ' Remove the events.
    RemoveHandler nDataGridView.CellMouseEnter, AddressOf OnDataGridViewCellMouseEnter
    RemoveHandler nDataGridView.KeyDown, AddressOf OnDataGridViewKeyDown
    RemoveHandler nDataGridView.CellDoubleClick, AddressOf myDataGridView_DoubleClick
    RemoveHandler nDataGridView.CellClick, AddressOf myDataGridView_Click

End Sub

这些事件非常简单且自明。通过调用来选择一个项目。

DirectCast(Me.Owner, ToolStripDropDown).Close(ToolStripDropDownCloseReason.ItemClicked)

重写 OnBoundsChangedDispose 子程序,以便在父 ToolStripDataGridView 调整大小时调整子 DataGridView 的大小,并在父 ToolStripDataGridView 处置时处置子 DataGridView

Protected Overrides Sub OnBoundsChanged()
    MyBase.OnBoundsChanged()
    If Not Me.Control Is Nothing Then
        DirectCast(Control, DataGridView).Size = Me.Size
        DirectCast(Control, DataGridView).AutoResizeColumns()
    End If
End Sub

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    MyBase.Dispose(disposing)
    If Not Me.Control Is Nothing AndAlso Not _
       DirectCast(Control, DataGridView).IsDisposed Then Control.Dispose()
End Sub

以上就是 ToolStripDataGridView 类的大部分内容:一个构造函数、四个简单的属性、四个简单的事件处理程序和四个简单的覆盖。总共 109 行代码(包括空格)。

创建自定义 ComboBox

控件的下一个核心部分是 AccGridComboBox 类本身,它显然继承自 ComboBox

AccGridComboBox 类有一个私有变量 myDropDown As ToolStripDropDown,它在类构造函数中实例化,并用作 ToolStripDataGridView 的容器。

ToolStripDataGridView 实例本身由 AddDataGridView 子程序设置。

Public Sub AddDataGridView(ByVal nDataGridView As DataGridView, ByVal nCloseOnSingleClick As Boolean)
    If Not myDataGridView Is Nothing Then Throw New Exception( _
        "Error. DataGridView is already assigned to the AccGridComboBox.")
    myDataGridView = New ToolStripDataGridView(nDataGridView, nCloseOnSingleClick)
    myDropDown.Width = Math.Max(Me.Width, myDataGridView.MinDropDownWidth)
    myDropDown.Height = nDataGridView.Height
    myDropDown.Items.Clear()
    myDropDown.Items.Add(Me.myDataGridView)
End Sub

AccGridComboBox 通过重写 WndProc 并拦截消息来处理下拉列表的显示。此方法的当前实现是从 CodeProject 文章 灵活的 ComboBox 和 EditingControl 中复制的,如果需要手动输入支持,则应进行更改,因为它会捕获组合框所有区域的点击,从而阻止文本输入。

Private Const WM_LBUTTONDOWN As UInt32 = &H201
Private Const WM_LBUTTONDBLCLK As UInt32 = &H203
Private Const WM_KEYF4 As UInt32 = &H134

Protected Overrides Sub WndProc(ByRef m As Message)

    '#Region "WM_KEYF4"
    If m.Msg = WM_KEYF4 Then
        Me.Focus()
        Me.myDropDown.Refresh()
        If Not Me.myDropDown.Visible Then

            ShowDropDown()

        Else
            myDropDown.Close()

        End If
        Return
    End If
    '#End Region

    '#Region "WM_LBUTTONDBLCLK"
    If m.Msg = WM_LBUTTONDBLCLK OrElse m.Msg = WM_LBUTTONDOWN Then
        If Not Me.myDropDown.Visible Then

            ShowDropDown()

        Else
            myDropDown.Close()

        End If
        Return
    End If
    '#End Region

    MyBase.WndProc(m)

End Sub

AccGridComboBox 中实际显示下拉列表的方法主要处理下拉列表的大小调整和选择合适的 DataGridView 行(包含当前 SelectedValue)。

Private Sub ShowDropDown()
        
    ' if a DataGridView is assigned
    If Not Me.myDataGridView Is Nothing Then
        
        ' just in case, though such situation is not supposed to happen
        If Not myDropDown.Items.Contains(Me.myDataGridView) Then
            myDropDown.Items.Clear()
            myDropDown.Items.Add(Me.myDataGridView)
        End If

        ' do sizing
        myDropDown.Width = Math.Max(Me.Width, Me.myDataGridView.MinDropDownWidth)
        myDataGridView.Size = myDropDown.Size
        myDataGridView.DataGridViewControl.Size = myDropDown.Size
        myDataGridView.DataGridViewControl.AutoResizeColumns()

        ' select DataGridViewRow that holds the currently selected value
        If _SelectedValue Is Nothing OrElse IsDBNull(_SelectedValue) Then
            myDataGridView.DataGridViewControl.CurrentCell = Nothing

        ElseIf Not Me.ValueMember Is Nothing AndAlso _
                   Not String.IsNullOrEmpty(Me.ValueMember.Trim) Then

            ' If ValueMember is set, look for the value by reflection
            
            If myDataGridView.DataGridViewControl.Rows.Count < 1 OrElse _
                myDataGridView.DataGridViewControl.Rows(0).DataBoundItem Is Nothing OrElse _
                myDataGridView.DataGridViewControl.Rows(0).DataBoundItem.GetType. _
                GetProperty(Me.ValueMember.Trim, _
                  BindingFlags.Public OrElse BindingFlags.Instance) Is Nothing Then

                myDataGridView.DataGridViewControl.CurrentCell = Nothing

            Else

                Dim CurrentValue As Object
                For Each r As DataGridViewRow In myDataGridView.DataGridViewControl.Rows
                    If Not r.DataBoundItem Is Nothing Then
                        CurrentValue = GetValueMemberValue(r.DataBoundItem)
                        If _SelectedValue = CurrentValue Then
                            myDataGridView.DataGridViewControl.CurrentCell = _
                                myDataGridView.DataGridViewControl.Item(0, r.Index)
                            Exit For
                        End If
                    End If
                Next

            End If

        Else
 
            ' If ValueMember is NOT set, look for the value by value or 
            
            Dim SelectionFound As Boolean = False
            For Each r As DataGridViewRow In myDataGridView.DataGridViewControl.Rows
                Try
                    ' try by value because it's faster and lookup
                    ' objects usualy implement equal operators
                    If _SelectedValue = r.DataBoundItem Then
                        myDataGridView.DataGridViewControl.CurrentCell = _
                            myDataGridView.DataGridViewControl.Item(0, r.Index)
                        SelectionFound = True
                        Exit For
                    End If
                Catch ex As Exception
                    Try
                        If _SelectedValue Is r.DataBoundItem Then
                            myDataGridView.DataGridViewControl.CurrentCell = _
                                myDataGridView.DataGridViewControl.Item(0, r.Index)
                            SelectionFound = True
                            Exit For
                        End If
                    Catch e As Exception
                    End Try
                End Try
            Next
            If Not SelectionFound Then _
                       myDataGridView.DataGridViewControl.CurrentCell = Nothing

        End If

        myDropDown.Show(Me, CalculatePoz) 

    End If

End Sub
    
' Helper method, tries geting ValueMember property value by reflection
Private Function GetValueMemberValue(ByVal DataboundItem As Object) As Object
    Dim newValue As Object = Nothing
    Try
        newValue = DataboundItem.GetType.GetProperty(Me.ValueMember.Trim, BindingFlags.Public _
            OrElse BindingFlags.Instance).GetValue(DataboundItem, Nothing)
    Catch ex As Exception
    End Try
    Return newValue
End Function

' Helper method, takes care of dropdown fitting the window
Private Function CalculatePoz() As Point

    Dim point As New Point(0, Me.Height)

    If (Me.PointToScreen(New Point(0, 0)).Y + Me.Height + Me.myDataGridView.Height) _
        > Screen.PrimaryScreen.WorkingArea.Height Then
        point.Y = -Me.myDataGridView.Height - 7
    End If

    Return point

End Function

AccGridComboBox 通过重载 SelectedValue 属性(绕过原生 ComboBox 逻辑)并提供自定义设置器方法,该方法允许通过 ValueMember 设置值对象,来处理设置当前值。

Private Sub SetValue(ByVal value As Object, ByVal IsValueMemberValue As Boolean)

    If value Is Nothing Then
        Me.Text = ""
        _SelectedValue = Nothing

    Else

        If Me.ValueMember Is Nothing OrElse String.IsNullOrEmpty(Me.ValueMember.Trim) _
            OrElse IsValueMemberValue Then

            Me.Text = value.ToString
            _SelectedValue = value

        Else

            Dim newValue As Object = GetValueMemberValue(value)

            ' If getting the ValueMember property value fails, try setting the object itself
            If newValue Is Nothing Then
                Me.Text = value.ToString
                _SelectedValue = value
            Else
                Me.Text = newValue.ToString
                _SelectedValue = newValue
            End If

        End If

    End If

End Sub

Private Sub ToolStripDropDown_Closed(ByVal sender As Object, _
            ByVal e As ToolStripDropDownClosedEventArgs)
    If e.CloseReason = ToolStripDropDownCloseReason.ItemClicked Then
        If Not MyBase.Focused Then MyBase.Focus()
        If myDataGridView.DataGridViewControl.CurrentRow Is Nothing Then
            SetValue(Nothing, False)
        Else
            SetValue(myDataGridView.DataGridViewControl.CurrentRow.DataBoundItem, False)
        End If
        MyBase.OnSelectedValueChanged(New EventArgs)
        ' If InstantBinding property is set to TRUE, force binding.
        If _InstantBinding Then
            For Each b As Binding In MyBase.DataBindings
                b.WriteValue()
            Next
        End If
    End If
End Sub

从上面的代码可以看出,AccGridComboBox 还实现了一个自定义属性 InstantBinding。它本身不是必需的,但在某些情况下,最好在值更改时而不是在验证后更新绑定。

以上是组合框控件本身所需的全部代码,但要使其准备好用作 IDataGridViewEditingControl,您还需要实现一些其他方法。

Protected Overridable ReadOnly Property DisposeToolStripDataGridView() As Boolean
    Get
        Return True
    End Get
End Property

Friend Sub AddToolStripDataGridView(ByVal nToolStripDataGridView As ToolStripDataGridView)
    If nToolStripDataGridView Is Nothing OrElse (Not myDataGridView Is Nothing _
        AndAlso myDataGridView Is nToolStripDataGridView) Then Exit Sub
    myDataGridView = nToolStripDataGridView
    myDropDown.Width = Math.Max(Me.Width, myDataGridView.MinDropDownWidth)
    myDropDown.Height = myDataGridView.DropDownHeight
    myDropDown.Items.Clear()
    myDropDown.Items.Add(Me.myDataGridView)
End Sub

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then
        If components IsNot Nothing Then components.Dispose()
        If DisposeToolStripDataGridView Then
            If Not myDropDown Is Nothing AndAlso Not _
                      myDropDown.IsDisposed Then myDropDown.Dispose()
            If Not myDataGridView Is Nothing AndAlso _
                Not myDataGridView.DataGridViewControl Is Nothing AndAlso _
                Not myDataGridView.DataGridViewControl.IsDisposed Then _
                myDataGridView.DataGridViewControl.Dispose()
            If Not myDataGridView Is Nothing AndAlso Not myDataGridView.IsDisposed Then _
                myDataGridView.Dispose()
        ElseIf Not DisposeToolStripDataGridView AndAlso Not myDropDown Is Nothing _
             AndAlso Not myDropDown.IsDisposed Then
            If Not myDataGridView Is Nothing Then myDropDown.Items.Remove(myDataGridView)
            myDropDown.Dispose()
        End If
    End If
    MyBase.Dispose(disposing)
End Sub

如果您有一个独立的 AccGridComboBox,那么在处置组合框本身时,最好同时处置托管的 ToolStripDropDownToolStripDataGridViewDataGridView 实例,因为 DataGridView 实例不能在不同窗体之间重用。另一方面,如果您有一个 AccGridComboBox 实例作为 DataGridView 列的一部分,您需要为该列的生命周期保留 DataGridView 实例,而不是组合框的生命周期(组合框实例在列的生命周期内被处置)。为了实现这两种行为,使用了受保护的可覆盖属性 DisposeToolStripDataGridView。此属性指示 Dispose 方法是否还应处置 ToolStripDataGridViewDataGridView 实例。除非被覆盖,否则它始终返回 true。它在 AccGridComboBoxEditingControl 类中被覆盖,而该类又被自定义 DataGridViewCell 使用。

创建自定义 IDataGridViewEditingControl、DataGridViewCell 和 DataGridViewColumn

MSDN 文章 如何:在 Windows Forms DataGridView 单元格中托管控件 详细介绍了创建自定义 DataGridViewColumn 的过程。因此,我只讨论特定于 AccGridComboBox 实现的代码部分。

AccGridComboBoxEditingControl 类的实现中,与上述 MSDN 文章中描述的实现相比,只有少数几个特定的方法。该类需要覆盖 DisposeToolStripDataGridView 属性(如前所述),以防止处置 DataGridView。该类还需要处理 SelectedValueChanged 事件,并向 DataGridView 基础结构通知更改。最后,值到文本的转换由基类 AccGridComboBox 处理,因此 GetEditingControlFormattedValue 的实现仅包含对 Text 属性的引用。

Protected Overrides ReadOnly Property DisposeToolStripDataGridView() As Boolean
    Get
        Return False
    End Get
End Property

Private Sub SelectedValueChangedHandler(ByVal sender As Object, _
            ByVal e As EventArgs) Handles Me.SelectedValueChanged
    If Not _hasValueChanged Then
        _hasValueChanged = True
        _dataGridView.NotifyCurrentCellDirty(True)
    End If
End Sub

Public Function GetEditingControlFormattedValue(ByVal context As DataGridViewDataErrorContexts) _
       As Object Implements _
       System.Windows.Forms.IDataGridViewEditingControl.GetEditingControlFormattedValue
    Return Me.Text
End Function

AccGridComboBoxDataGridViewCell 类的实现中,与上述 MSDN 文章中描述的实现相比,只有少数几个特定的方法。由于此单元格将处理不同的对象类型,因此 ValueType 属性返回最通用的类型——Object。另外两个方法是自明的,负责初始化 AccGridComboBox 编辑控件,以及获取和设置单元格值。

Public Overrides ReadOnly Property ValueType() As Type
    Get
        Return GetType(Object)
    End Get
End Property
 
Public Overrides Sub InitializeEditingControl(ByVal nRowIndex As Integer, _
    ByVal nInitialFormattedValue As Object, ByVal nDataGridViewCellStyle As DataGridViewCellStyle)

    MyBase.InitializeEditingControl(nRowIndex, nInitialFormattedValue, nDataGridViewCellStyle)

    Dim cEditBox As AccGridComboBox = TryCast(Me.DataGridView.EditingControl, AccGridComboBox)

    If cEditBox IsNot Nothing Then

        If Not MyBase.OwningColumn Is Nothing AndAlso Not DirectCast(MyBase.OwningColumn, _
            DataGridViewAccGridComboBoxColumn).ComboDataGridView Is Nothing Then

            ' Add the common column ToolStripDataGridView and set common properties
            cEditBox.AddToolStripDataGridView(DirectCast(MyBase.OwningColumn, _
                DataGridViewAccGridComboBoxColumn).GetToolStripDataGridView)
            cEditBox.ValueMember = DirectCast(MyBase.OwningColumn, _
                     DataGridViewAccGridComboBoxColumn).ValueMember
            cEditBox.InstantBinding = DirectCast(MyBase.OwningColumn, _
                     DataGridViewAccGridComboBoxColumn).InstantBinding

            End If
 
        ' try to set current value
        Try
            cEditBox.SelectedValue = Value
        Catch ex As Exception
            cEditBox.SelectedValue = Nothing
        End Try

    End If

End Sub

Protected Overrides Function SetValue(ByVal rowIndex As Integer, ByVal value As Object) As Boolean
    If Not Me.DataGridView Is Nothing AndAlso Not Me.DataGridView.EditingControl Is Nothing _
        AndAlso TypeOf Me.DataGridView.EditingControl Is AccGridComboBox Then
        Return MyBase.SetValue(rowIndex, DirectCast(Me.DataGridView.EditingControl, _
            AccGridComboBox).SelectedValue)
    Else
        Return MyBase.SetValue(rowIndex, value)
    End If
End Function

最后,DataGridViewAccGridComboBoxColumn 类仅实现镜像 AccGridComboBox 属性的属性,并负责处置关联的网格。

Private myDataGridView As ToolStripDataGridView = Nothing
Public Property ComboDataGridView() As DataGridView
    Get
        If Not myDataGridView Is Nothing Then Return myDataGridView.DataGridViewControl
        Return Nothing
    End Get
    Set(ByVal value As DataGridView)
        If Not value Is Nothing Then
            myDataGridView = New ToolStripDataGridView(value, _CloseOnSingleClick)
        Else
            myDataGridView = Nothing
        End If
    End Set
End Property

Private _ValueMember As String = ""
Public Property ValueMember() As String
    Get
        Return _ValueMember
    End Get
    Set(ByVal value As String)
        _ValueMember = value
    End Set
End Property

Private _CloseOnSingleClick As Boolean = True
Public Property CloseOnSingleClick() As Boolean
    Get
        Return _CloseOnSingleClick
    End Get
    Set(ByVal value As Boolean)
        _CloseOnSingleClick = value
        If Not myDataGridView Is Nothing Then _
           myDataGridView.CloseOnSingleClick = value
    End Set
End Property

Private _InstantBinding As Boolean = True
Public Property InstantBinding() As Boolean
    Get
        Return _InstantBinding
    End Get
    Set(ByVal value As Boolean)
        _InstantBinding = value
    End Set
End Property

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then
        If Not myDataGridView Is Nothing _
            AndAlso Not myDataGridView.DataGridViewControl Is Nothing _
            AndAlso Not myDataGridView.DataGridViewControl.IsDisposed Then _
            myDataGridView.DataGridViewControl.Dispose()
        If Not myDataGridView Is Nothing AndAlso Not myDataGridView.IsDisposed Then _
            myDataGridView.Dispose()
    End If
    MyBase.Dispose(disposing)
End Sub
© . All rights reserved.