自定义DataGridView多选下拉列已保存值重新加载后不显示问题
自定义DataGridView多值选择下拉框列显示异常问题
我自定义了一个DataGridView列,可展示下拉框实现多值选择,选中值会以分隔符拼接展示。
目前功能整体运行正常,但已保存的值不会在单元格中展示:选中值后实时展示正常,重新加载后单元格变为空白。
我猜测是遗漏了初始化Me.Value的事件处理程序。
列类代码
Imports System.Data Imports System.ComponentModel Public Class dgvCheckedComboBoxColumn Inherits DataGridViewColumn Private m_dt As DataTable <Browsable(True), Category("Daten"), Description("Only DataTable allowed!")> Public Shadows Property DataSource() As DataTable Get Return m_dt End Get Set(value As DataTable) m_dt = value End Set End Property Private m_DisplayMember As String <Browsable(True), Category("Daten"), Description("The column that contains the displayed value in the dropdown")> Public Shadows Property DisplayMember() As String Get Return m_DisplayMember End Get Set(value As String) m_DisplayMember = value End Set End Property Private m_ValueMember As String <Browsable(True), Category("Daten"), Description("ValueMember")> Public Shadows Property ValueMember As String Get Return m_ValueMember End Get Set(value As String) m_ValueMember = value 'Primary-Key von DataSource entspricht Value-Member If Me.DataSource IsNot Nothing Then m_dt.PrimaryKey = New DataColumn() {m_dt.Columns(value)} End If End Set End Property Private m_CellDisplayMember As String <Browsable(True), Category("Daten"), Description("Displayed Cell-Value")> Public Property CellDisplayMember As String Get Return If(String.IsNullOrEmpty(m_CellDisplayMember), m_DisplayMember, m_CellDisplayMember) End Get Set(value As String) m_CellDisplayMember = value End Set End Property Private m_DropDownWidth As Integer <DefaultValue(150), Browsable(True), Category("Visual"), Description("DropDown-Width")> Public Property DropDownWidth As Integer Get Return m_DropDownWidth End Get Set(value As Integer) m_DropDownWidth = value End Set End Property Private m_UseValidation As Boolean <DefaultValue(False), Browsable(True), Category("Data"), Description("Only allow values that exist in datasource")> Public Property UseValidation As Boolean Get Return m_UseValidation End Get Set(value As Boolean) m_UseValidation = value End Set End Property Public Sub New() MyBase.New(New dgvCheckedComboBoxCell()) Me.CellTemplate = New dgvCheckedComboBoxCell Me.ReadOnly = True End Sub Public Overrides Function Clone() As Object Dim copy As dgvCheckedComboBoxColumn = TryCast(MyBase.Clone(), dgvCheckedComboBoxColumn) copy.DataSource = m_dt copy.ValueMember = m_ValueMember copy.DisplayMember = m_DisplayMember copy.CellDisplayMember = m_CellDisplayMember copy.DropDownWidth = m_DropDownWidth copy.UseValidation = m_UseValidation Return copy End Function End Class
自定义单元格代码
Imports System.Data Public Class dgvCheckedComboBoxCell Inherits DataGridViewTextBoxCell Private m_ucCheckList As UserControl Public Sub New() MyBase.New() End Sub #Region " Properties" Private m_CheckedValues As DataTable ''' <summary> ''' Contains the selected values from current cell ''' </summary> ''' <returns></returns> Public Property CheckedValues As DataTable Get Dim col As dgvCheckedComboBoxColumn = CType(Me.OwningColumn, dgvCheckedComboBoxColumn) If m_CheckedValues Is Nothing AndAlso col.DataSource IsNot Nothing Then Dim dt As DataTable = DirectCast(col.DataSource, DataTable).Clone m_CheckedValues = dt End If Return m_CheckedValues End Get Set(value As DataTable) m_CheckedValues = value End Set End Property ''' <summary> ''' Contains the selected values separated by String by ValueMember ''' </summary> ''' <returns></returns> Private ReadOnly Property SelectedValue As String Get Dim col = DirectCast(Me.OwningColumn, dgvCheckedComboBoxColumn) Try Return String.Join(",", CheckedValues?.Rows.Cast(Of DataRow).Select(Function(r) r.Item(col.ValueMember).ToString)) Catch ex As Exception Return "" End Try End Get End Property Private ReadOnly Property SelectedText As String Get Dim col = DirectCast(Me.OwningColumn, dgvCheckedComboBoxColumn) Try Return String.Join(",", CheckedValues?.Rows.Cast(Of DataRow).Select(Function(r) r.Item(col.CellDisplayMember).ToString)) Catch ex As Exception Return "" End Try End Get End Property #End Region #Region " Cell-Events" Protected Overrides Sub OnMouseEnter(rowIndex As Integer) MyBase.OnMouseEnter(rowIndex) End Sub Protected Overrides Sub OnEnter(rowIndex As Integer, throughMouseClick As Boolean) MyBase.OnEnter(rowIndex, throughMouseClick) End Sub Protected Overrides Sub OnLeave(rowIndex As Integer, throughMouseClick As Boolean) If DataGridView.Controls.Contains(m_ucCheckList) Then m_ucCheckList.Visible = False End If Me.Value = Me.SelectedValue MyBase.OnLeave(rowIndex, throughMouseClick) End Sub Protected Overrides Sub OnMouseClick(e As DataGridViewCellMouseEventArgs) MyBase.OnMouseClick(e) OpenDropDown() End Sub Private Sub OpenDropDown(Optional CursorLocation As Point = Nothing) Try If Me.DataGridView.Columns.Count = 0 Or RowIndex = -1 Then Exit Sub End If Dim col As dgvCheckedComboBoxColumn = CType(Me.OwningColumn, dgvCheckedComboBoxColumn) If col.DataSource Is Nothing OrElse CType(col.DataSource, DataTable).Rows.Count = 0 Then Exit Sub If m_ucCheckList Is Nothing Then m_ucCheckList = New UserControl m_ucCheckList.Padding = New Padding(5, 0, 0, 0) m_ucCheckList.BorderStyle = BorderStyle.FixedSingle End If If Not IsNothing(CursorLocation) Then Dim ctrl = DataGridView.GetChildAtPoint(CursorLocation, GetChildAtPointSkip.Disabled) End If SetDefaultLocationOfListBox() Dim chk As CheckBox m_ucCheckList.Controls.Clear() For Each row As DataRow In DirectCast(col.DataSource, DataTable).Rows chk = New CheckBox chk.Text = row(col.DisplayMember).ToString chk.Tag = row chk.Checked = (From dr In CheckedValues.AsEnumerable Where CStr(dr(col.ValueMember)) = CStr(row(col.ValueMember)) Select True).FirstOrDefault chk.Dock = DockStyle.Top AddHandler chk.CheckedChanged, AddressOf ChkList_CheckedChanged m_ucCheckList.Controls.Add(chk) Next With m_ucCheckList If CType(col.DataSource, DataTable).Rows.Count > 20 Then .Height = 250 Else .Height = CType(col.DataSource, DataTable).Rows.Count * m_ucCheckList.Controls(0).Height End If .Width = col.DropDownWidth If .Height < 24 Then .Height = 24 End If .Show() .BringToFront() .Refresh() End With Catch ex As Exception End Try End Sub Private Sub SetDefaultLocationOfListBox() Dim defaultPoint As Point Try defaultPoint = GetCurrentCellPosition() m_ucCheckList.Location = defaultPoint If Not Me.DataGridView.Controls.Contains(m_ucCheckList) Then Me.DataGridView.Controls.Add(m_ucCheckList) End If m_ucCheckList.Visible = True Catch ex As Exception End Try End Sub Private Function GetCurrentCellPosition() As Point Try If Me.DataGridView IsNot Nothing AndAlso DataGridView.CurrentCell IsNot Nothing Then Dim iRowHeight As Integer = DataGridView.Rows(DataGridView.CurrentCell.RowIndex).Height Dim rCellRectangle As Rectangle = DataGridView.GetCellDisplayRectangle(DataGridView.CurrentCell.ColumnIndex, DataGridView.CurrentCell.RowIndex, False) Return New Point(rCellRectangle.X, rCellRectangle.Y + iRowHeight) End If Catch ex As Exception End Try End Function Protected Overrides Sub Paint(graphics As Graphics, clipBounds As Rectangle, cellBounds As Rectangle, rowIndex As Integer, cellstate As DataGridViewElementStates, value As Object, formattedValue As Object, errorText As String, cellStyle As DataGridViewCellStyle, advancedBorderStyle As DataGridViewAdvancedBorderStyle, paintParts As DataGridViewPaintParts) 'formattedValue = SelectedText 'value = SelectedValue MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellstate, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts) End Sub Private Sub ChkList_CheckedChanged(sender As Object, e As EventArgs) Dim chk As CheckBox = CType(sender, CheckBox) Dim row As DataRow = CType(chk.Tag, DataRow) Dim col = CType(Me.OwningColumn, dgvCheckedComboBoxColumn) If chk.Checked Then Dim dr = CheckedValues.NewRow() dr(col.ValueMember) = row(col.ValueMember) dr(col.DisplayMember) = row(col.DisplayMember) If col.CellDisplayMember <> col.DisplayMember Then dr(col.CellDisplayMember) = row(col.CellDisplayMember) End If m_CheckedValues.Rows.Add(dr) Else Dim CheckedRow = (From dr In CheckedValues.AsEnumerable Where CStr(dr(col.ValueMember)) = CStr(row(col.ValueMember)) Select dr).FirstOrDefault If CheckedRow IsNot Nothing Then CheckedValues.Rows.Remove(CheckedRow) End If End If End Sub Protected Overrides Sub OnKeyPress(e As KeyPressEventArgs, rowIndex As Integer) MyBase.OnKeyPress(e, rowIndex) End Sub #End Region End Class
更新:我已经找到问题根源,值在Paint事件中被覆盖了,完成Bug修复后我会更新对应代码。
内容的提问来源于stack exchange,提问作者Stevy G.
相关产品推荐
相关产品推荐

