DataGridView中的VB.NET更新问题TimePicker:输入键不更新显示的值 [英] VB.NET Update Issue in DataGridView Cell for TimePicker: Enter Key Does not Update Displayed Value
问题描述
我有一个好奇的问题,在VB.NET中重载DataGridView的单元格以使用DateTimePicker(允许用户选择日期和时间)。我采用了 Microsoft实施日历选择器并修改它是日历和时间选择器。当我输入新的日期并按ENTER键时,DataGridView单元格中显示的日期是旧的日期。
只有在该键再次按ENTER时,或点击该单元格,然后单击,显示新值。
如果单击单元格,输入新日期,此单元格将显示适当的日期时间值,然后点击进入另一个单元格。然后,显示的日期与我输入的日期相符。它正在使用我有问题的ENTER键。
我修改了Microsoft重载的代码如下:
公共类TimeColumn
继承DataGridViewColumn
Public Sub New()
MyBase.New(New TimeCell())
结束Sub
公共覆盖属性CellTemplate()作为DataGridViewCell
获取
返回MyBase.CellTemplate
结束获取
设置(ByVal值作为DataGridViewCell)
'确保用于模板的单元格是TimeCell。
If(value IsNot Nothing)AndAlso _
Not value.GetType()。IsAssignableFrom(GetType(TimeCell))_
然后
抛出新的InvalidCastException(必须是TimeCell )
End If
MyBase.CellTemplate = value
结束集
结束属性
结束类
公共类TimeCell
继承DataGridViewTextBoxCell
Public Sub New()
'使用短日期格式。
Me.Style.Format =MM / dd / yy h:mm tt
'm_isTime = True
End Sub
公开覆盖Sub InitializeEditingControl(ByVal rowIndex As Integer,_
ByVal initialFormattedValue As Object,_
ByVal dataGridViewCellStyle As DataGridViewCellStyle)
'将编辑控件的值设置为当前单元格值。
MyBase.InitializeEditingControl(rowIndex,initialFormattedValue,_
dataGridViewCellStyle)
Dim ctl As New TimeEditingControl
ctl = CType(DataGridView.EditingControl,TimeEditingControl)
ctl.CustomFormat =MM / dd / yyyy h:mm tt
Me.Value = ctl.Value
End Sub
公共覆盖ReadOnly属性EditType( )As Type
Get
'返回TimeCell使用的编辑轮廓的类型。
返回GetType(TimeEditingControl)
结束获取
结束属性
公共覆盖ReadOnly属性ValueType()作为类型
获取
'返回TimeCell包含的值的类型。
返回GetType(DateTime)
结束获取
结束属性
公共覆盖ReadOnly属性DefaultNewRowValue()As Object
获取
'使用当前日期和时间为默认值。
返回DateTime.Now
结束获取
结束属性
结束类
类TimeEditingControl
继承DateTimePicker
实现IDataGridViewEditingControl
私有dataGridViewControl作为DataGridView
私有值IsChanged As Boolean = False
Private rowIndexNum As Integer
Public Sub New()
Me .Format = DateTimePickerFormat.Custom
End Sub
公共属性EditingControlFormattedValue()As Object _
实现IDataGridViewEditingControl.EditingControlFormattedValue
获取
返回Me.Value。 ToShortDateString()
结束Get
Set(ByVal value As Object)
如果TypeOf的值为String然后
Me.Value = DateTime.Parse(CStr(value) )
结束如果
结束集
结束属性
公共函数GetEditingControlFormatted Value(ByVal context _
As DataGridViewDataErrorContexts)As Object _
实现IDataGridViewEditingControl.GetEditingControlFormattedValue
Dim result,tempDateTime As DateTime
tempDateTime = Me.Value
返回tempDateTime.ToString
结束函数
公共Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As _
DataGridViewCellStyle)_
实现IDataGridViewEditingControl.ApplyCellStyleToEditingControl
Me.Font = dataGridViewCellStyle.Font
Me.CalendarForeColor = dataGridViewCellStyle.ForeColor
Me.CalendarMonthBackground = dataGridViewCellStyle.BackColor
End Sub
公共属性EditingControlRowIndex()As Integer _
实现IDataGridViewEditingControl.EditingControlRowIndex
获取
返回rowIndexNum
结束Get
Set(ByVal value As Integer)
rowIndexNum = value
结束集
结束属性
公共函数EditingControlWantsInputKey(ByVal key As Keys,_
ByVal dataGridViewWantsInputKey As Boolean)As Boolean _
实现IDataGridViewEditingControl.EditingControlWantsInputKey
Dim lDateTime As DateTime
'让DateTimePicker处理钥匙列出
选择键和Keys.KeyCode
案例Keys.Enter
Console.WriteLine(DateTime.Now.ToString&。& DateTime.Now。 Millisecond.ToString&:EditingControlWantsInputKey - Detected [ENTER] key。)
End选择
valueIsChanged = True
Console.WriteLine(EditingControlWantsInputKey(& Me.Value& ))
Dim lDataGridView1 As DataGridView
lDataGridView1 = Me.dataGridViewControl
lDataGridView1.BeginEdit(True)
lDataGridView1.BeginEdit(False)
返回True
结束函数
Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean)_
实现IDataGridViewEditingControl.PrepareEditingControlForEdit
'无需准备做完了。
End Sub
公共ReadOnly属性RepositionEditingControlOnValueChange()_
作为Boolean实现_
IDataGridViewEditingControl.RepositionEditingControlOnValueChange
获取
返回False
结束获取
结束属性
公共属性EditingControlDataGridView()作为DataGridView _
实现IDataGridViewEditingControl.EditingControlDataGridView
获取
返回dataGridViewControl
结束Get
Set(ByVal value As DataGridView)
dataGridViewControl = value
结束集
结束属性
公共属性EditingControlValueChanged()As Boolean _
实现IDataGridViewEditingControl.EditingControlValueChanged
获取
返回值IsChanged
结束获取
Set(ByVal值As Boolean)
valueIsChanged = value
结束集
结束属性
公共ReadOnly属性EditingControlCursor()As Cursor _
实现IDataGridViewEditingControl.EditingPanelCursor
获取
返回MyBase.Cursor
结束获取
结束属性
受保护的覆盖Sub OnValueChanged(ByVal eventargs As EventArgs)
'通知DataGridView单元格的内容已更改。
valueIsChanged = True
Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
MyBase.OnValueChanged(eventargs)
End Sub
结束类
我的发现到目前为止:
-
有趣的是,公共属性EditingControlValueChanged()作为布尔实现IDataGridViewEditingControl.EditingControlValueChanged 根本没有检测到ENTER键!您可以看到我为该事件输入了一些调试代码,看看它是否检测到按下ENTER键。
-
事件 Public Property EditingControlValueChanged()由于布尔实现IDataGridViewEditingControl.EditingControlValueChanged 不会检测到值更改(布尔值IsChanged设置为false),直到第二次按ENTER键,此时它被设置为true。
-
我也尝试更新DataGridView的CellEndEdit事件中的单元格值,但是没有起作用。
- p>我已经更新了我的Visual Studio Express 2013,以防它是Micosoft错误。
任何想法如何获得显示的值以匹配按ENTER键输入的内容?谢谢。
我的初始评论绝对是错误的。在重现你的问题之后,我注意到有趣/令人沮丧的事情:在下面的一行的 EditingControlWantsInputKey
方法中放置一个断点,允许更新按预期发生(调试修复的问题):
选择键And Keys.KeyCode
这是非常烦人的,在我的沮丧中,我连续疯狂地测试了月份条目:1,2,3,...,12
这是当我注意到:10-12月更新正确。其实输入01正确更新。我随后的研究结果导致我进入了本文的评论部分,其中用户Dean Wiles在其评论中标题为使用Tab或Enter 丢失的更改提供这个Microsoft支持源,这表明:
提高了[DateTimePicker]的ValueChanged事件只有在
后,您才能输入以下任何一项:
- 一年中的所有数字。
- 一天的所有数字。
- 一个月的所有数字。
这可以通过将以下vb.net版本的代码添加到您的 TimeEditingControl
类来解决:
受保护的覆盖函数ProcessCmdKey(ByRef msg As Message,keyData As Keys)As Boolean
选择案例keyData和Keys.KeyCode
案例Keys.Enter,Keys.Tab
Me.dataGridViewControl.Focus()
退出选择
结束选择
返回MyBase.ProcessCmdKey(msg,keyData)
结束函数
I am having a curious issue with overloading a cell of the DataGridView in VB.NET to use a DateTimePicker (allows user to select both a date and a time). I took the Microsoft implementation of a Calendar picker and modified it be both a Calendar and Time picker. When I enter a new date and press the ENTER key, the displayed date in the DataGridView cell is the old date.
It's only when press ENTER again on that key, or click on that cell and click away that the new value is displayed.
This cell does display the proper date-time value if I click on the cell, enter a new date, and click away onto another cell. Then, the displayed date matches what I inputted. It's using the ENTER key that I am having issues with.
I modified the Microsoft overloaded code as follows:
Public Class TimeColumn
Inherits DataGridViewColumn
Public Sub New()
MyBase.New(New TimeCell())
End Sub
Public Overrides Property CellTemplate() As DataGridViewCell
Get
Return MyBase.CellTemplate
End Get
Set(ByVal value As DataGridViewCell)
' Ensure that the cell used for the template is a TimeCell.
If (value IsNot Nothing) AndAlso _
Not value.GetType().IsAssignableFrom(GetType(TimeCell)) _
Then
Throw New InvalidCastException("Must be a TimeCell")
End If
MyBase.CellTemplate = value
End Set
End Property
End Class
Public Class TimeCell
Inherits DataGridViewTextBoxCell
Public Sub New()
' Use the short date format.
Me.Style.Format = "MM/dd/yy h:mm tt"
'm_isTime = True
End Sub
Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer, _
ByVal initialFormattedValue As Object, _
ByVal dataGridViewCellStyle As DataGridViewCellStyle)
' Set the value of the editing control to the current cell value.
MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, _
dataGridViewCellStyle)
Dim ctl As New TimeEditingControl
ctl = CType(DataGridView.EditingControl, TimeEditingControl)
ctl.CustomFormat = "MM/dd/yyyy h:mm tt"
Me.Value = ctl.Value
End Sub
Public Overrides ReadOnly Property EditType() As Type
Get
' Return the type of the editing contol that TimeCell uses.
Return GetType(TimeEditingControl)
End Get
End Property
Public Overrides ReadOnly Property ValueType() As Type
Get
' Return the type of the value that TimeCell contains.
Return GetType(DateTime)
End Get
End Property
Public Overrides ReadOnly Property DefaultNewRowValue() As Object
Get
' Use the current date and time as the default value.
Return DateTime.Now
End Get
End Property
End Class
Class TimeEditingControl
Inherits DateTimePicker
Implements IDataGridViewEditingControl
Private dataGridViewControl As DataGridView
Private valueIsChanged As Boolean = False
Private rowIndexNum As Integer
Public Sub New()
Me.Format = DateTimePickerFormat.Custom
End Sub
Public Property EditingControlFormattedValue() As Object _
Implements IDataGridViewEditingControl.EditingControlFormattedValue
Get
Return Me.Value.ToShortDateString()
End Get
Set(ByVal value As Object)
If TypeOf value Is String Then
Me.Value = DateTime.Parse(CStr(value))
End If
End Set
End Property
Public Function GetEditingControlFormattedValue(ByVal context _
As DataGridViewDataErrorContexts) As Object _
Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
Dim result, tempDateTime As DateTime
tempDateTime = Me.Value
Return tempDateTime.ToString
End Function
Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As _
DataGridViewCellStyle) _
Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl
Me.Font = dataGridViewCellStyle.Font
Me.CalendarForeColor = dataGridViewCellStyle.ForeColor
Me.CalendarMonthBackground = dataGridViewCellStyle.BackColor
End Sub
Public Property EditingControlRowIndex() As Integer _
Implements IDataGridViewEditingControl.EditingControlRowIndex
Get
Return rowIndexNum
End Get
Set(ByVal value As Integer)
rowIndexNum = value
End Set
End Property
Public Function EditingControlWantsInputKey(ByVal key As Keys, _
ByVal dataGridViewWantsInputKey As Boolean) As Boolean _
Implements IDataGridViewEditingControl.EditingControlWantsInputKey
Dim lDateTime As DateTime
' Let the DateTimePicker handle the keys listed.
Select key And Keys.KeyCode
Case Keys.Enter
Console.WriteLine(DateTime.Now.ToString & "." & DateTime.Now.Millisecond.ToString & ": EditingControlWantsInputKey--Detected [ENTER] key.")
End Select
valueIsChanged = True
Console.WriteLine("EditingControlWantsInputKey (" & Me.Value & ")")
Dim lDataGridView1 As DataGridView
lDataGridView1 = Me.dataGridViewControl
lDataGridView1.BeginEdit(True)
lDataGridView1.BeginEdit(False)
Return True
End Function
Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean) _
Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
' No preparation needs to be done.
End Sub
Public ReadOnly Property RepositionEditingControlOnValueChange() _
As Boolean Implements _
IDataGridViewEditingControl.RepositionEditingControlOnValueChange
Get
Return False
End Get
End Property
Public Property EditingControlDataGridView() As DataGridView _
Implements IDataGridViewEditingControl.EditingControlDataGridView
Get
Return dataGridViewControl
End Get
Set(ByVal value As DataGridView)
dataGridViewControl = value
End Set
End Property
Public Property EditingControlValueChanged() As Boolean _
Implements IDataGridViewEditingControl.EditingControlValueChanged
Get
Return valueIsChanged
End Get
Set(ByVal value As Boolean)
valueIsChanged = value
End Set
End Property
Public ReadOnly Property EditingControlCursor() As Cursor _
Implements IDataGridViewEditingControl.EditingPanelCursor
Get
Return MyBase.Cursor
End Get
End Property
Protected Overrides Sub OnValueChanged(ByVal eventargs As EventArgs)
' Notify the DataGridView that the contents of the cell have changed.
valueIsChanged = True
Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
MyBase.OnValueChanged(eventargs)
End Sub
End Class
My findings so far:
What's curious is that Public Property EditingControlValueChanged() As Boolean Implements IDataGridViewEditingControl.EditingControlValueChanged does not detect the ENTER key at all! You can see I entered some debugging code for that event to see if it detects the ENTER key being pressed.
The event Public Property EditingControlValueChanged() As Boolean Implements IDataGridViewEditingControl.EditingControlValueChanged does not detect the value change (the boolean valueIsChanged is set to false) until the second time the ENTER key is pressed, at which point it is set to true.
I tried also updating the cell value in the CellEndEdit event for the DataGridView, but that didn't work.
I already updated my Visual Studio Express 2013 in case it was a Micosoft bug.
Any ideas how to get the displayed value to match what was entered upon hitting the ENTER key? Thanks.
My initial comment was definitely wrong. After reproducing your problem, I noticed something funny/frustrating: placing a breakpoint within the EditingControlWantsInputKey
method on the following line, allowed the updates to occur as expected (a debugging fix of the problem):
Select key And Keys.KeyCode
That was beyond annoying and in my frustration, I frantically tested month entries in succession: 1, 2, 3, ..., 12
That's when I noticed: months 10-12 updated correctly. In fact, entering 01 updated correctly. My subsequent research led me to the comments section of this article, where user Dean Wiles in his comment titled Changes lost using Tab or Enter provides this Microsoft support source which indicates that:
The ValueChanged event of the [DateTimePicker] is raised only after you type any one of the following:
- All the digits of a year.
- All the digits of a day.
- All the digits of a month.
And this can be addressed by adding the following vb.net version of his code to your TimeEditingControl
class:
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
Select Case keyData And Keys.KeyCode
Case Keys.Enter, Keys.Tab
Me.dataGridViewControl.Focus()
Exit Select
End Select
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
这篇关于DataGridView中的VB.NET更新问题TimePicker:输入键不更新显示的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!