2013-03-15 49 views
0

我有下面的代碼,當用戶改變對我的「結束」日期DateTinePicker控制權的日期運行:VB.NET 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 
     MessageBox.Show("The end date should be after the start date", Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error) 
     dtpEndDate.Value = Today 
    End If 
End Sub 

這個過程似乎是兩次運行,因爲在MessageBox被顯示兩次。

我有錯事件,還是有一些更好的管理方式?

我試圖用一個變量進行編輯的建議:

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被修改時觸發一次,日期在開始日期之前。

感謝

菲利普

+0

why dtpEndDate.Value = Today? – andy 2013-03-15 11:43:01

+0

好吧,這確實是要取消更改... – 2013-03-15 12:03:13

+0

如果今天,這將顯示一個'MessageBox'兩次。如果你同時使用'AddHandler'和'Handles',它也可能觸發多次。 – JosephHirn 2013-03-15 12:30:26

回答

3

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 
+0

首先,謝謝你教我,但是,雖然你的第一種方法確實可以防止控件顯示錯誤的日期,但是沒有消息告訴用戶爲什麼控件不顯示選擇的日期 - 我錯過了什麼? – 2013-03-15 12:55:07

+1

您會看到一個錯誤圖標,看起來像一個停止交通標誌。將鼠標懸停在其上以獲取錯誤消息。非常微妙。如果你更喜歡面對你的信息,那麼使用我提出的第二個解決方案。 – 2013-03-15 13:04:02

+0

我確實添加了一個dtpStartDate_ValueChanged事件來清除或顯示錯誤,如果用戶選擇錯誤地設置StartDate選擇器! – 2013-03-15 13:12:11

0

這曾經發生在我身上。

可以證明你在的WebForms處理至少在兩個地方的事件:在ASP頁面,並在後面的代碼。如果我在後面的代碼中的「dtpEndDate_ValueChanged」方法的簽名之後有句柄「Handles dtpEndDate.ValueChanged」,那麼我不必在aspx中寫入「OnClick =」dtpEndDate_ValueChanged「」或類似的東西。

當您在的WinForms中的WebForms,而不是是,確保你沒有

< < 的AddHandler dtpEndDate.ValueChanged,AddressOf Me.dtpEndDate_ValueChanged >>

或類似的東西Load方法或其他地方的某處。

希望它能幫助,

伊夫

0

要麼你可以使用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)然後以an的形式定義一個布爾變量d將該值設置爲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 

末次

+0

當我使用_validating_事件時,我被困在現在,它似乎沒有起火。 signaturee是** Private Sub dtpEndDate_Validating(ByVal sender As Object,ByVal e As System.ComponentModel.CancelEventArgs)處理dtpEndDate.Validating **,但即使我有斷點,它也不會觸發。 – 2013-03-15 12:14:41

+0

是否有可能我弄亂了設計器代碼? – 2013-03-15 12:15:01

+0

是的,這是正確的,但不是我想要的。我傾向於嘗試在結束日期的數據時間選擇器在開始日期的日期之前顯示錯誤 – 2013-03-15 12:38:05

0

嘗試了這一點,

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較小,因此會有通過使用上面的代碼不會發生邏輯衝突。

+0

我試過這段代碼,但它仍然運行兩次,或者顯示消息框兩次 - 可能是因爲我將值更改爲「今天」? – 2013-03-15 12:19:50

+0

@Philip你可以顯示你用作輸入的日期嗎? – 2013-03-15 12:27:34

+0

感謝您的幫助,但我喜歡Hans提出的ErroProvider解決方案! – 2013-03-15 13:14:12