B
Billy Jacobs
I have created a DataGridColumnDatePicker Component so
that I can put a datetimepicker control in my datagrid.
It almost works.
When I put my mouse in the cell it changes to a
datetimepicker control. I can then select a date which
displays in the cell. When I leave the cell however I get
the following error:
Error Caption: Error when committing the row to the
original data store.
Error Message: Object reference not set to an instance of
an object. Do you want to correct the value.
Here is my class. (At the ver bottom are the declarations
for the grid control in my form)
Public Class DataGridColumnDatePicker
Inherits DataGridTextBoxColumn
Private WithEvents myDatePicker As DateTimePicker
Private cm As CurrencyManager
Private iCurrentRow As Int32
Public Sub New(ByVal Container As
System.ComponentModel.IContainer)
MyClass.New()
'Required for Windows.Forms Class Composition
Designer support
Container.Add(Me)
Me.cm = Nothing
'Create datetimepicker and force DropDownList
style
Me.myDatePicker = New DateTimePicker
myDatePicker.Format = DateTimePickerFormat.Short
' Add event handler for notification of when
ComboBox loses focus
End Sub
' On myDatePicker Value changed, set the column
value, hide the date time picker,
' and unregister scroll event handler
Private Sub Change_Value(ByVal sender As Object,
ByVal e As EventArgs) Handles myDatePicker.ValueChanged
'Dim rowView As DataRowView = CType(CType
(Me.myDatePicker.Value.ToShortDateString, Object),
DataRowView)
'Dim s As String = CType(rowView.Row
(Me.myDatePicker.Value), String)
Try
Dim s As String =
Me.myDatePicker.Value.ToShortDateString
Debug.WriteLine(String.Format("Leave: {0}
{1}", Me.myDatePicker.Value.ToShortTimeString, s))
SetColumnValueAtRow(Me.cm, Me.iCurrentRow, s)
Invalidate()
Me.myDatePicker.Hide()
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Sub
Public Sub New()
MyBase.New()
'This call is required by the Component Designer.
InitializeComponent()
'Add any initialization after the
InitializeComponent() call
End Sub
'Component overrides dispose to clean up the
component list.
Protected Overloads Overrides Sub Dispose(ByVal
disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Component Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the
Component Designer
'It can be modified using the Component Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private
Sub InitializeComponent()
components = New System.ComponentModel.Container
End Sub
Protected Overrides Function GetColumnValueAtRow
(ByVal source As System.Windows.Forms.CurrencyManager,
ByVal rowNum As Integer) As Object
Return MyBase.GetColumnValueAtRow(source, rowNum)
End Function
' Given a row and a display member, iterating over
bound datasource to find
' the associated value member. Set this value member.
' Protected Overloads Sub SetColumnValueAtRow(ByVal
source As System.Windows.Forms.CurrencyManager, ByVal
rowNum As Int32, ByVal value As Object)
'Debug.WriteLine(String.Format("SetColumnValueAtRow
{0} {1}", rowNum, value));
'object s = value;
'// Iterate through the datasource bound to the
ColumnComboBox
'// Don't confuse this datasource with the datasource
of the associated datagrid
' CurrencyManager(cm = (CurrencyManager))
' (this.DataGridTableStyle.DataGrid.BindingContext
[this.comboBox.DataSource]);
'// Assumes the associated DataGrid is bound to a
DataView, or DataTable that
'// implements a default DataView
'DataView dataview = ((DataView)cm.List);
'int i;
'for (i = 0; i < dataview.Count; i++)
'{
' if (s.Equals(dataview
[this.comboBox.DisplayMember]))
' break;
'}
'// If set item was found return corresponding value,
otherwise return DbNull.Value
' If (i < DataView.Count) Then
' s = dataview[this.comboBox.ValueMember];
' Else
' s = DBNull.Value;
'base.SetColumnValueAtRow(source, rowNum, s);
' End Sub
Protected Overrides Sub Abort(ByVal rowNum As Integer)
MyBase.Abort(rowNum)
End Sub
Protected Overrides Function Commit(ByVal dataSource
As System.Windows.Forms.CurrencyManager, ByVal rowNum As
Integer) As Boolean
Try
MyBase.Commit(dataSource, rowNum)
Catch ex As Exception
Throw New Exception("Error in Commit: " &
ex.Message, ex.InnerException)
End Try
End Function
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)
Try
Debug.WriteLine(String.Format("Edit {0}",
rowNum))
MyBase.Edit(source, rowNum, bounds,
[readOnly], instantText, cellIsVisible)
If Not [readOnly] AndAlso cellIsVisible Then
' Save current row in the datagrid and
currency manager associated with
' the data source for the datagrid
Me.iCurrentRow = rowNum
Me.cm = source
'Add event handler for datagrid scroll
notification
AddHandler
Me.DataGridTableStyle.DataGrid.Scroll, AddressOf
DataGrid_Scroll
' Site the datetimepicker control within
the bounds of the current cell
Me.myDatePicker.Parent = Me.TextBox.Parent
Dim rect As Rectangle =
Me.DataGridTableStyle.DataGrid.GetCurrentCellBounds()
Me.myDatePicker.Location = rect.Location
Me.myDatePicker.Size = New Size
(Me.TextBox.Size.Width, Me.myDatePicker.Size.Height)
' Set combo box selection to given text
'If Me.TextBox.Text <> vbNull Then
If Me.TextBox.Text <> "(null)" Then
Me.myDatePicker.Value = CType
(Me.TextBox.Text, Date)
Else
Me.myDatePicker.Value = Now.Date
End If
' Make the datetime picker visible and
place on top text box control
Me.myDatePicker.Show()
Me.myDatePicker.BringToFront()
Me.myDatePicker.Focus()
End If
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Sub
Private Sub date_Time_Picker_Leave(ByVal sender As
Object, ByVal e As EventArgs) Handles myDatePicker.Leave
Try
'Dim rowView As DataRowView = CType(CType
(Me.myDatePicker.Value.ToShortDateString, Object),
DataRowView)
'Dim s As String = CType(rowView.Row
(Me.myDatePicker.Value), String)
Dim s As String =
Me.myDatePicker.Value.ToShortDateString
Debug.WriteLine(String.Format("Leave: {0}
{1}", Me.myDatePicker.Value.ToShortDateString, s))
SetColumnValueAtRow(Me.cm, Me.iCurrentRow, s)
Me.TextBox.Text = s
Invalidate()
Me.myDatePicker.Hide()
RemoveHandler
Me.DataGridTableStyle.DataGrid.Scroll, AddressOf
DataGrid_Scroll
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Sub
Private Sub DataGrid_Scroll(ByVal sender As Object,
ByVal e As EventArgs)
Try
Debug.WriteLine("Scroll")
Me.myDatePicker.Hide()
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Sub
Protected Overrides Function GetMinimumHeight() As
Integer
Try
Return MyBase.GetMinimumHeight
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Function
Protected Overrides Function GetPreferredHeight(ByVal
g As System.Drawing.Graphics, ByVal value As Object) As
Integer
Try
Return MyBase.GetPreferredHeight(g, value)
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Function
Protected Overrides Function GetPreferredSize(ByVal g
As System.Drawing.Graphics, ByVal value As Object) As
System.Drawing.Size
Try
Return MyBase.GetPreferredSize(g, value)
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
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)
Try
MyBase.Paint(g, bounds, source, rowNum)
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
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)
Try
MyBase.Paint(g, bounds, source, rowNum,
alignToRight)
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Sub
End Class
***Form Code***
Friend WithEvents DataGridTableStyle1 As
System.Windows.Forms.DataGridTableStyle
Friend WithEvents DataGridDateTimePicker1 As
DataGridColumnDatePicker
Me.DataGridTableStyle1.GridColumnStyles.AddRange(New
System.Windows.Forms.DataGridColumnStyle() {
Me.DataGridDateTimePicker1})
Me.DataGridDateTimePicker1 = New
CSEPP_Admin_Tool.DataGridColumnDatePicker(Me.components)
Me.DataGridDateTimePicker1.Format = ""
Me.DataGridDateTimePicker1.FormatInfo = Nothing
Me.DataGridDateTimePicker1.HeaderText = "Date"
Me.DataGridDateTimePicker1.MappingName
= "EntryDate"
Me.DataGridDateTimePicker1.Width = 75
that I can put a datetimepicker control in my datagrid.
It almost works.
When I put my mouse in the cell it changes to a
datetimepicker control. I can then select a date which
displays in the cell. When I leave the cell however I get
the following error:
Error Caption: Error when committing the row to the
original data store.
Error Message: Object reference not set to an instance of
an object. Do you want to correct the value.
Here is my class. (At the ver bottom are the declarations
for the grid control in my form)
Public Class DataGridColumnDatePicker
Inherits DataGridTextBoxColumn
Private WithEvents myDatePicker As DateTimePicker
Private cm As CurrencyManager
Private iCurrentRow As Int32
Public Sub New(ByVal Container As
System.ComponentModel.IContainer)
MyClass.New()
'Required for Windows.Forms Class Composition
Designer support
Container.Add(Me)
Me.cm = Nothing
'Create datetimepicker and force DropDownList
style
Me.myDatePicker = New DateTimePicker
myDatePicker.Format = DateTimePickerFormat.Short
' Add event handler for notification of when
ComboBox loses focus
End Sub
' On myDatePicker Value changed, set the column
value, hide the date time picker,
' and unregister scroll event handler
Private Sub Change_Value(ByVal sender As Object,
ByVal e As EventArgs) Handles myDatePicker.ValueChanged
'Dim rowView As DataRowView = CType(CType
(Me.myDatePicker.Value.ToShortDateString, Object),
DataRowView)
'Dim s As String = CType(rowView.Row
(Me.myDatePicker.Value), String)
Try
Dim s As String =
Me.myDatePicker.Value.ToShortDateString
Debug.WriteLine(String.Format("Leave: {0}
{1}", Me.myDatePicker.Value.ToShortTimeString, s))
SetColumnValueAtRow(Me.cm, Me.iCurrentRow, s)
Invalidate()
Me.myDatePicker.Hide()
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Sub
Public Sub New()
MyBase.New()
'This call is required by the Component Designer.
InitializeComponent()
'Add any initialization after the
InitializeComponent() call
End Sub
'Component overrides dispose to clean up the
component list.
Protected Overloads Overrides Sub Dispose(ByVal
disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Component Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the
Component Designer
'It can be modified using the Component Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private
Sub InitializeComponent()
components = New System.ComponentModel.Container
End Sub
Protected Overrides Function GetColumnValueAtRow
(ByVal source As System.Windows.Forms.CurrencyManager,
ByVal rowNum As Integer) As Object
Return MyBase.GetColumnValueAtRow(source, rowNum)
End Function
' Given a row and a display member, iterating over
bound datasource to find
' the associated value member. Set this value member.
' Protected Overloads Sub SetColumnValueAtRow(ByVal
source As System.Windows.Forms.CurrencyManager, ByVal
rowNum As Int32, ByVal value As Object)
'Debug.WriteLine(String.Format("SetColumnValueAtRow
{0} {1}", rowNum, value));
'object s = value;
'// Iterate through the datasource bound to the
ColumnComboBox
'// Don't confuse this datasource with the datasource
of the associated datagrid
' CurrencyManager(cm = (CurrencyManager))
' (this.DataGridTableStyle.DataGrid.BindingContext
[this.comboBox.DataSource]);
'// Assumes the associated DataGrid is bound to a
DataView, or DataTable that
'// implements a default DataView
'DataView dataview = ((DataView)cm.List);
'int i;
'for (i = 0; i < dataview.Count; i++)
'{
' if (s.Equals(dataview
[this.comboBox.DisplayMember]))
' break;
'}
'// If set item was found return corresponding value,
otherwise return DbNull.Value
' If (i < DataView.Count) Then
' s = dataview[this.comboBox.ValueMember];
' Else
' s = DBNull.Value;
'base.SetColumnValueAtRow(source, rowNum, s);
' End Sub
Protected Overrides Sub Abort(ByVal rowNum As Integer)
MyBase.Abort(rowNum)
End Sub
Protected Overrides Function Commit(ByVal dataSource
As System.Windows.Forms.CurrencyManager, ByVal rowNum As
Integer) As Boolean
Try
MyBase.Commit(dataSource, rowNum)
Catch ex As Exception
Throw New Exception("Error in Commit: " &
ex.Message, ex.InnerException)
End Try
End Function
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)
Try
Debug.WriteLine(String.Format("Edit {0}",
rowNum))
MyBase.Edit(source, rowNum, bounds,
[readOnly], instantText, cellIsVisible)
If Not [readOnly] AndAlso cellIsVisible Then
' Save current row in the datagrid and
currency manager associated with
' the data source for the datagrid
Me.iCurrentRow = rowNum
Me.cm = source
'Add event handler for datagrid scroll
notification
AddHandler
Me.DataGridTableStyle.DataGrid.Scroll, AddressOf
DataGrid_Scroll
' Site the datetimepicker control within
the bounds of the current cell
Me.myDatePicker.Parent = Me.TextBox.Parent
Dim rect As Rectangle =
Me.DataGridTableStyle.DataGrid.GetCurrentCellBounds()
Me.myDatePicker.Location = rect.Location
Me.myDatePicker.Size = New Size
(Me.TextBox.Size.Width, Me.myDatePicker.Size.Height)
' Set combo box selection to given text
'If Me.TextBox.Text <> vbNull Then
If Me.TextBox.Text <> "(null)" Then
Me.myDatePicker.Value = CType
(Me.TextBox.Text, Date)
Else
Me.myDatePicker.Value = Now.Date
End If
' Make the datetime picker visible and
place on top text box control
Me.myDatePicker.Show()
Me.myDatePicker.BringToFront()
Me.myDatePicker.Focus()
End If
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Sub
Private Sub date_Time_Picker_Leave(ByVal sender As
Object, ByVal e As EventArgs) Handles myDatePicker.Leave
Try
'Dim rowView As DataRowView = CType(CType
(Me.myDatePicker.Value.ToShortDateString, Object),
DataRowView)
'Dim s As String = CType(rowView.Row
(Me.myDatePicker.Value), String)
Dim s As String =
Me.myDatePicker.Value.ToShortDateString
Debug.WriteLine(String.Format("Leave: {0}
{1}", Me.myDatePicker.Value.ToShortDateString, s))
SetColumnValueAtRow(Me.cm, Me.iCurrentRow, s)
Me.TextBox.Text = s
Invalidate()
Me.myDatePicker.Hide()
RemoveHandler
Me.DataGridTableStyle.DataGrid.Scroll, AddressOf
DataGrid_Scroll
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Sub
Private Sub DataGrid_Scroll(ByVal sender As Object,
ByVal e As EventArgs)
Try
Debug.WriteLine("Scroll")
Me.myDatePicker.Hide()
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Sub
Protected Overrides Function GetMinimumHeight() As
Integer
Try
Return MyBase.GetMinimumHeight
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Function
Protected Overrides Function GetPreferredHeight(ByVal
g As System.Drawing.Graphics, ByVal value As Object) As
Integer
Try
Return MyBase.GetPreferredHeight(g, value)
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Function
Protected Overrides Function GetPreferredSize(ByVal g
As System.Drawing.Graphics, ByVal value As Object) As
System.Drawing.Size
Try
Return MyBase.GetPreferredSize(g, value)
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
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)
Try
MyBase.Paint(g, bounds, source, rowNum)
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
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)
Try
MyBase.Paint(g, bounds, source, rowNum,
alignToRight)
Catch ex As Exception
Throw New Exception(ex.Message,
ex.InnerException)
End Try
End Sub
End Class
***Form Code***
Friend WithEvents DataGridTableStyle1 As
System.Windows.Forms.DataGridTableStyle
Friend WithEvents DataGridDateTimePicker1 As
DataGridColumnDatePicker
Me.DataGridTableStyle1.GridColumnStyles.AddRange(New
System.Windows.Forms.DataGridColumnStyle() {
Me.DataGridDateTimePicker1})
Me.DataGridDateTimePicker1 = New
CSEPP_Admin_Tool.DataGridColumnDatePicker(Me.components)
Me.DataGridDateTimePicker1.Format = ""
Me.DataGridDateTimePicker1.FormatInfo = Nothing
Me.DataGridDateTimePicker1.HeaderText = "Date"
Me.DataGridDateTimePicker1.MappingName
= "EntryDate"
Me.DataGridDateTimePicker1.Width = 75