I have been working on a custom datagridcolumnstyle that uses a combo box when in edit mode. It the box is showing, but not expanded and I click on another cell in the same row, I get a null reference exception without source code. If I click on another row I get an object not set to reference error, but it shows a dialog box. If I expand the combo box it works just fine. I am thinking it is an internal bug, but how do I work around it?
I would show code, but it is way to large. Here is the style code though.
I would show code, but it is way to large. Here is the style code though.
Public Class HSDropBoxColumn Inherits DataGridColumnStyle Implements IColumnInterface Implements ISetCellFormat Friend WithEvents mListBox As New ComboBox Private mDataGrid As DataGrid = Nothing Private mblnIsEditing As Boolean = False Public Sub New(ByVal Values As String()) mListBox.Items.AddRange(Values) mListBox.Visible = False mListBox.Height = 50 mListBox.DropDownStyle = ComboBoxStyle.DropDownList End Sub Protected Overrides Sub Abort(rowNum As Integer) mblnIsEditing = False mDataGrid.Controls.Remove(mListBox) Invalidate() End Sub Protected Overrides Function Commit(dataSource As System.Windows.Forms.CurrencyManager, rowNum As Integer) As Boolean If Not mblnIsEditing Then Return True End If If mListBox Is Nothing Then Return True mblnIsEditing = False Dim objOld, objNew As Object Try objOld = GetColumnValueAtRow(dataSource, rowNum) Catch exr As IndexOutOfRangeException Return True Exit Function End Try Try objNew = mListBox.SelectedItem.ToString Catch ex As Exception Return True End Try If objOld Is DBNull.Value And objNew Is DBNull.Value Then Return False ElseIf objOld Is DBNull.Value And Not objNew Is DBNull.Value Then If TypeOf objNew Is String Then SetColumnValueAtRow(dataSource, rowNum, CStr(objNew)) OnCellValueChanged(New CellValueChangedEventArgs(rowNum, Me.DataGridTableStyle.GridColumnStyles.IndexOf(Me), objOld, objNew)) Else Return False End If ElseIf Not objOld Is DBNull.Value And objNew Is DBNull.Value Then SetColumnValueAtRow(dataSource, rowNum, DBNull.Value) OnCellValueChanged(New CellValueChangedEventArgs(rowNum, Me.DataGridTableStyle.GridColumnStyles.IndexOf(Me), objOld, objNew)) ElseIf Not objOld Is DBNull.Value And Not objNew Is DBNull.Value Then If TypeOf objOld Is String And TypeOf objNew Is String Then If CStr(objOld) <> CStr(objNew) Then SetColumnValueAtRow(dataSource, rowNum, CStr(objNew)) OnCellValueChanged(New CellValueChangedEventArgs(rowNum, Me.DataGridTableStyle.GridColumnStyles.IndexOf(Me), objOld, objNew)) Else Return False End If End If End If Invalidate() Me.mListBox.Visible = False Return True End Function Protected Overrides Function GetMinimumHeight() As Integer Return mListBox.PreferredHeight + 4 End Function Protected Overrides Function GetPreferredHeight(g As System.Drawing.Graphics, value As Object) As Integer Return mListBox.PreferredHeight + 4 End Function Protected Overrides Function GetPreferredSize(g As System.Drawing.Graphics, value As Object) As System.Drawing.Size Return New Size(100, mListBox.PreferredHeight + 4) End Function Protected Overloads Overrides 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) Paint(g, bounds, [source], rowNum, False) End Sub Protected Overloads Overrides 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 alignToRight As Boolean) Paint(g, bounds, [source], rowNum, Brushes.Red, _ Brushes.Blue, alignToRight) End Sub Protected Overloads Overrides Sub Paint(ByVal g As Graphics, _ ByVal bounds As Rectangle, ByVal [source] As CurrencyManager, _ ByVal rowNum As Integer, ByVal backBrush As Brush, _ ByVal foreBrush As Brush, ByVal alignToRight As Boolean) Dim e As HSDataGridFormatCellEventArgs = Nothing Dim pintCol As Integer = 0 Try e = New HSDataGridFormatCellEventArgs(rowNum, pintCol, Me.GetColumnValueAtRow([source], rowNum)) RaiseEvent SetCellFormat(Me, e) Catch ex As Exception End Try Dim pstrVal As String = String.Empty Try pintCol = Me.DataGridTableStyle.GridColumnStyles.IndexOf(Me) Catch ex As Exception End Try If TypeOf source.Current Is DataRowView Then Dim drv As DataRowView = DirectCast(source.Current, DataRowView) Dim r As DataRow = drv.DataView.Table.Rows(rowNum) End If g.FillRectangle(backBrush, bounds) 'RaiseEvent SetCellFormat(Me, e) ' assume we will call the baseclass Dim callBaseClass As Boolean = True Dim pbrshBackBrush As SolidBrush Dim pbrshForeBrush As SolidBrush ' check the brushes returned from the event If Not (e.BackBrush Is Nothing) Then pbrshBackBrush = e.BackBrush Else pbrshBackBrush = New SolidBrush(Color.White) End If If Not (e.ForeBrush Is Nothing) Then pbrshForeBrush = e.ForeBrush Else pbrshForeBrush = New SolidBrush(Color.Black) End If Me.DataGridTableStyle.HeaderBackColor = e.HeaderBackColor Me.DataGridTableStyle.HeaderForeColor = e.HeaderForeColor Me.DataGridTableStyle.GridLineColor = e.GridLineColor ' check the UseBaseClassDrawing property If Not e.UseBaseClassDrawing Then callBaseClass = False End If If e.CurrentCellValue Is DBNull.Value Then pstrVal = "[null]" Else pstrVal = CStr(e.CurrentCellValue) End If Try g.FillRectangle(pbrshBackBrush, bounds) Dim pt As New PointF Dim f As Font = Me.DataGridTableStyle.DataGrid.Font Dim siz As SizeF = g.MeasureString(pstrVal, f) Dim psngTop As Single = (bounds.Height \ 2) - (siz.Height \ 2) psngTop = bounds.Top + psngTop Dim r As New RectangleF(bounds.X, psngTop, bounds.Width, siz.Height) Dim sf As New StringFormat If alignToRight Then sf.LineAlignment = StringAlignment.Far Else sf.LineAlignment = StringAlignment.Near End If g.DrawString(pstrVal, f, pbrshForeBrush, r, sf) sf.Dispose() Catch ex As Exception End Try End Sub Protected Overrides Sub SetDataGridInColumn(ByVal value As DataGrid) MyBase.SetDataGridInColumn(value) If Not value Is Nothing Then mDataGrid = value End If End Sub Protected Overridable Sub OnCellValueChanged(ByVal e As CellValueChangedEventArgs) RaiseEvent CellValueChanged(Me, e) End Sub Protected Overloads Overrides Sub Edit(ByVal source As System.Windows.Forms.CurrencyManager, ByVal rowNum As Integer, ByVal bounds As System.Drawing.Rectangle, ByVal [readOnly] As Boolean, ByVal instantText As String, ByVal cellIsVisible As Boolean) Dim objVal As Object = GetColumnValueAtRow([source], rowNum) Dim value As String = String.Empty If Not TypeOf objVal Is DBNull Then value = CStr(objVal) End If If mListBox Is Nothing Then Exit Sub mDataGrid.Controls.Add(mListBox) If cellIsVisible Then mListBox.Width = bounds.Width mListBox.Location = bounds.Location mListBox.Height = 50 mListBox.SelectedItem = value mListBox.Visible = True Else mListBox.SelectedItem = value mListBox.Visible = False End If If mListBox.Visible Then DataGridTableStyle.DataGrid.Invalidate(bounds) End If Me.mblnIsEditing = True mListBox.Focus() End Sub Public Event CellValueChanged(sender As Object, e As CellValueChangedEventArgs) Implements IColumnInterface.CellValueChanged Public Event SetCellFormat(sender As Object, e As HSDataGridFormatCellEventArgs) Implements ISetCellFormat.SetCellFormat End Class
Last edited by a moderator: