【问题标题】:VB.NET WinForms Date Time Picker change event runs twice?VB.NET WinForms 日期时间选择器更改事件运行两次?
【发布时间】:2013-03-15 11:35:55
【问题描述】:

当用户更改我的“结束”日期 DateTinePicker 控件上的日期时,我会运行以下代码:

Private Sub dtpEndDate_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dtpEndDate.ValueChanged
    If dtpEndDate.Value.Date < dtpStartDate.Value.Date Then
        MessageBox.Show("The end date should be after the start date", Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
        dtpEndDate.Value = Today
    End If
End Sub

这个过程似乎运行了两次,因为消息框显示了两次。

我有错误的事件,还是有更好的方法来管理它?

我尝试按照建议使用变量对其进行编辑:

Private Sub dtpEndDate_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dtpEndDate.ValueChanged

If m_blndtpEndDateIsDone = False Then
    If dtpEndDate.Value.Date < dtpStartDate.Value.Date Then
        MessageBox.Show("The end date should be after the start date", Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
        m_blndtpEndDateIsDone = True
        dtpEndDate.Value = Today
    Else
        m_blndtpEndDateIsDone = False
    End If
Else
    m_blndtpEndDateIsDone = False
End If
wnd sub

不幸的是它仍然会发射两次......

我希望每次修改结束日期 dtpicker 并且日期早于开始日期时触发一次。

谢谢

菲利普

【问题讨论】:

  • 为什么 dtpEndDate.Value = 今天?
  • 嗯,真的是要取消改动了……
  • 如果Today &lt; dtpStartDate.Value.Date,这将显示MessageBox 两次。如果您同时使用AddHandlerHandles,它也可能会触发多次。
  • @GLOIERTECH。是的,我已经尝试了所有提供的选项,现在正在尝试 @Hans Passant 建议的 ErrorProvider 选项

标签: vb.net winforms datepicker controls


【解决方案1】:

MessageBox 像这样会很麻烦。它将焦点从控件上移开并泵出自己的消息循环。这可能会导致 重新进入 问题,这种问题使 DoEvents() 如此臭名昭著。 DateTimePicker 控件不是为了很好地处理这个问题而编写的,它通常是一种笨拙的控件。

一个简单的解决方法是避免面对面的错误报告。 ErrorProvider 组件可以很好地做到这一点。在你的表单上放一个,让你的代码看起来像这样:

Private Sub dtpEndDate_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dtpEndDate.ValueChanged
    If dtpEndDate.Value.Date < dtpStartDate.Value.Date Then
        ErrorProvider1.SetError(dtpEndDate, "The end date should be after the start date")
        dtpEndDate.Value = Today
    Else
        ErrorProvider1.SetError(dtpEndDate, "")
    End If
End Sub

您实际上可以避免 MessageBox 创建的重入问题,您可以通过在 DateTimePicker 完成自己的事件处理之后稍后显示它来做到这一点。使用 Control.BeginInvoke() 在 Winforms 中优雅地完成。让它看起来像这样:

Private Sub dtpEndDate_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dtpEndDate.ValueChanged
    If dtpEndDate.Value.Date < dtpStartDate.Value.Date Then
        Me.BeginInvoke(New MethodInvoker(AddressOf reportDateProblem))
        dtpEndDate.Value = Today
    End If
End Sub

Private Sub reportDateProblem()
    MessageBox.Show("The end date should be after the start date", Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
End Sub

【讨论】:

  • 首先,感谢您教我,但是,尽管您的第一种方法确实可以防止控件显示错误的日期,但没有向用户显示控件为什么不显示所选日期的消息- 我错过了什么?
  • 您看到一个错误图标,看起来像一个停止交通标志。将鼠标悬停在它上面以获取错误消息。很微妙。如果您更喜欢面对面的信息,请使用我提出的第二种解决方案。
  • 我确实添加了一个 dtpStartDate_ValueChanged 事件,以便在用户选择错误地设置 StartDate 选择器时也清除或显示错误!
【解决方案2】:

你可以使用dtpEndDate_Validating事件

Private Sub dtpEndDate_Validating(sender As Object, e As CancelEventArgs)
    If dtpEndDate.Value.[Date] < dtpStartDate.Value.[Date] Then
        MessageBox.Show("The end date should be after the start date", Me.Text, MessageBoxButtons.OK, MessageBoxIcon.[Error])
    End If
   e.Cancel = True
End Sub

如果您想使用您的事件(dtpEndDate_ValueChanged),则在表单中定义一个布尔变量并将值设置为 false。在您执行第一次消息框后的事件中,将变量设置为 true。并检查这个变量

Dim isDone As Boolean = False

Private Sub dtpEndDate_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dtpEndDate.ValueChanged
If Not isDone Then
 If dtpEndDate.Value.Date < dtpStartDate.Value.Date Then
    MessageBox.Show("The end date should be after the start date", Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
    IsDone = True
    dtpEndDate.Value = Today
 End If
End If

结束子

【讨论】:

  • 当我使用 validating 事件时,我现在卡住了,它似乎没有触发。签名是 Private Sub dtpEndDate_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles dtpEndDate.Validating 但即使我有断点它也不会触发。
  • 是的,没错,但不是我想要的。当结束日期的数据时间选择器早于开始日期的日期时,我更愿意尝试让它显示错误
  • 然后用我给出的第二种方法............你的代码中的一点点变化......
  • 感谢您的帮助,但我喜欢下面Hans提出的ErroProvider解决方案!
【解决方案3】:

这曾经发生在我身上。

您可以证明您至少在 WebForms 中的两个位置处理事件:在 asp 页面中和在后面的代码中。如果我在后面代码中的“dtpEndDate_ValueChanged”方法的签名之后有语法“Handles dtpEndDate.ValueChanged”,那么我不必在我的aspx中写“OnClick =“dtpEndDate_ValueChanged”或类似的东西。

当您在 WinForms 中而不是在 WebForms 中时,请确保您没有

AddHandler dtpEndDate.ValueChanged, AddressOf Me.dtpEndDate_ValueChanged>>

或者在 Load 方法中的某处或其他地方类似的东西。

希望对你有帮助,

伊夫

【讨论】:

    【解决方案4】:

    试试这个,

    Private Sub dtpEndDate_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dtpEndDate.ValueChanged
    
         If (dtpEndDate.Value.Date < dtpStartDate.Value.Date) And Not dtpEndDate.Value = Today Then
                MessageBox.Show("The end date should be after the start date", Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
                dtpEndDate.Value = Today
         End If
    
     End Sub
    

    您正在通过today's date 重置dtpEndDate 上的日期,因此您的dtpStartDate 应该小于today,因此使用上述代码不会发生逻辑冲突。

    【讨论】:

    • 我尝试了这段代码,但它仍然运行了两次,或者显示了两次消息框 - 可能是因为我将值更改为 Today ?
    • 感谢您的帮助,但我喜欢下面Hans提出的ErroProvider解决方案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-01
    • 1970-01-01
    相关资源
    最近更新 更多