I have a bound DataGridView1 and several bound TextBoxes and DateTimePickers.
Everything is working well, except when I try to accomplish these two things in conjunction
Since the BindingSource data source can be sorted, use the BindingSource.Sort property instead of sorting the control (your DataGridView). columnName
is the name of the Column used for sorting (you can specify more than one Column):
myBindingSource.Sort = $"{columnName} ASC"
Then, when the User sets the DateTimePicker.Value
, update the Cell value, corresponding to DateTime
Column of the current Row, using the ValueChanged
event:
Method 1: Bound DateTimePicker
In the DateTimePicker.ValueChanged
, the BindingSource.EndEdit() method is called, to apply immediately the new value to the data source.
Note 1: for this method to work as expected, the BindingSource data source must be a DataTable or another container that implements the IEditableObject interface.
DateTimePicker1.DataBindings.Add(
New Binding("Value", myBindingSource, "MyDateTimeColumn", False, DataSourceUpdateMode.OnValidation))
'(...)
Private Sub DateTimePicker1_ValueChanged(sender As Object, e As EventArgs) Handles DateTimePicker1.ValueChanged
myBindingSource.EndEdit()
End Sub
Note 2: the DateTimePicker doesn't support a null
/DbNull
value. If the DataSouce may contain DBNull
values, it may become erratic. You'll probably need to create a custom control from it, to manage its behavior. Otherwise, see Method 2
Method 2: UnBound DateTimePicker
The userSetValue
field is used when setting the DateTimePicker value in code, to prevent the procedure in the ValueChanged
event to update the DateTime Columns's Value. This way, the event will only update the Column when a User changes the date manually.
Private columnName As String = String.Empty
Private userSetValue As Boolean = True
Private Sub DateTimePicker1_ValueChanged(sender As Object, e As EventArgs) Handles DateTimePicker1.ValueChanged
If (Not userSetValue) Then Return
If (DataGridView1.CurrentRow Is Nothing) OrElse
(DataGridView1.CurrentRow.Cells($"{columnName}").ValueType IsNot GetType(Date)) Then Return
'DataGridView1.SuspendLayout()
DataGridView1.CurrentRow.Cells($"{columnName}").Value = DateTimePicker1.Value
myBindingSource.EndEdit()
'DataGridView1.ResumeLayout(False)
End Sub
► Test both methods with and without SuspendLayout()
/ ResumeLayout()
.
The RowPostPaint
event (for example) can be used to update the DateTimePicker.Value
the associated Columns' value:
Private Sub DataGridView1_RowPostPaint(sender As Object, e As DataGridViewRowPostPaintEventArgs) Handles DataGridView1.RowPostPaint
userSetValue = False
Dim currentValue = DataGridView1.CurrentRow.Cells("MyDateTimeColumn").Value
If currentValue Is Nothing OrElse currentValue Is DBNull.Value Then currentValue = Date.Now
DateTimePicker1.Value = DirectCast(currentValue, Date)
userSetValue = True
End Sub
Using any of the two methods, this is the result: