- - PR -
イベント内でのメッセージボックス使用による再入について
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2006-04-07 15:28
WinXP_SP1+VB.NET2003でデスクトップアプリケーションを開発しています。
メインフォームでSystem.Windows.Forms.DateTimePickerを使用しています。 DateTimePicker.ValueChangedイベントで処理を行い、処理内容によって MessageBoxを表示させ、分岐させています。このMessageBox表示時の イベント再入で無限ループに入ってしまい、困っています。 月を変更する"矢印"を押すと"矢印を押した"というイベント? が完了する前にMessageBoxを表示してしまうせいか、 ValueChangedイベント処理関数に何回も処理が入ってしまいます。 (DateTimePickerは矢印を押した方向に月更新が連続で進んでいます。) [コード例] Public DatePicker as DateTimePicker Private Sub DatePicker_ValueChanged(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles DatePicker.ValueChanged '何かの処理 if MessageBox.Show("Test", "Test", MessageBoxButtons.YesNoCancel) _ = MsgBoxResult.Yes then '分岐の処理 end if End Sub 'コード5行目のMessageBox処理から別のイベントが2行目に再入してきます。 内容的にはこのスレッドと近いです。 [VB.NET タイマーイベントにて] http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=29364&forum=7&start=8 私自身もWindows.Form.Timerで同じ経験を過去にして、その時はTimer使用を 辞めました(Threadに置き換えたと思います)。今回は逃げ方に困っています。 MessageBoxを辞めれば良いのですが、イベント処理内でMessageBoxを 使用できないのは些か残念です。 上記のような状況で、再入を防ぐ良いアイデアを何方か御存知でしたら 教えて頂けると助かります。長文失礼致しました。 | ||||||||
|
投稿日時: 2006-04-07 16:32
以下のように実装しましたが、再現しませんでした。
「別のイベント」とは何でしょうか? _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||||||
|
投稿日時: 2006-04-07 16:50
返信有難うございます。別のイベントとは、上手く表現できないのですが、
MessageBoxを表示したイベントとは別に、メインフォームに渡されたイベント、という意味です。日にち選択では発生しないのですが、月表示をスクロール させると発生してしまいます。以下のようなコードでスタックトレースを 見てみました。 [コード例] Dim i As Integer Private Sub DateTimePicker1_ValueChanged(略) Try i += 1 If i = 1 or i = 3 Then '場合によってコメントアウトして下さい。 Throw New Exception("Error " & i & " kaime") End If Trace.WriteLine("Count=" & i) MsgBox("test" & i) Catch ex As Exception Trace.Fail(ex.Message) End Try End Sub | ||||||||
|
投稿日時: 2006-04-07 17:02
日にち "選択" と月を "スクロール" では比較するに値しないような気がするので良くわかりませんが、
うまく説明できないのであれば、ミニマム コードを書いて頂けませんか? イベントに目星が付いているならば、コメント アウトなどしてミニマム テストもされていると思いますし。 _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||||||
|
投稿日時: 2006-04-07 17:14
すみません、tabを空白に置き換えなかったので左によってしまいました・・・
処理がループしている時のスタックトレースの結果です。 非常に長く、判り辛くて申し訳ありません。 at Form1.DateTimePicker1_ValueChanged(〜略〜) D:\〜略〜 ↑ 2回目のForm内関数の呼出です。 at DateTimePicker.OnValueChanged(EventArgs eventargs) at DateTimePicker.WmDateTimeChange(Message& m) at DateTimePicker.WmReflectCommand(Message& m) at DateTimePicker.WndProc(Message& m) at ControlNativeWindow.OnMessage(Message& m) at ControlNativeWindow.WndProc(Message& m) at NativeWindow.DebuggableCallback(IntPtr hWnd, _ Int32 msg, IntPtr wparam, IntPtr lparam) at UnsafeNativeMethods.SendMessage(HandleRef hWnd, _ Int32 msg, IntPtr wParam, IntPtr lParam) at Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam) at Control.ReflectMessageInternal(IntPtr hWnd, Message& m) at Control.WmNotify(Message& m) at Control.WndProc(Message& m) at ScrollableControl.WndProc(Message& m) at ContainerControl.WndProc(Message& m) at Form.WndProc(Message& m) at ControlNativeWindow.OnMessage(Message& m) at ControlNativeWindow.WndProc(Message& m) at NativeWindow.DebuggableCallback(IntPtr hWnd, _ Int32 msg, IntPtr wparam, IntPtr lparam) at UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, _ IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam) at NativeWindow.DefWndProc(Message& m) at Control.DefWndProc(Message& m) at Control.WmNotify(Message& m) at Control.WndProc(Message& m) at DateTimePicker.WndProc(Message& m) at ControlNativeWindow.OnMessage(Message& m) at ControlNativeWindow.WndProc(Message& m) at NativeWindow.DebuggableCallback(IntPtr hWnd, _ Int32 msg, IntPtr wparam, IntPtr lparam) ↑ 再度、イベントをキャッチしてます。 at SafeNativeMethods.MessageBox(HandleRef hWnd, _ String text, String caption, Int32 type) at MessageBox.ShowCore(〜略〜) at MessageBox.Show(〜略〜) ← MessageBoxの表示です at Interaction.MsgBox(Object Prompt, MsgBoxStyle Buttons, Object Title) at Form1.DateTimePicker1_ValueChanged(〜略〜) D:\〜略〜 ↑ 1回目のForm内関数の呼出です。 at DateTimePicker.OnValueChanged(EventArgs eventargs) at DateTimePicker.WmDateTimeChange(Message& m) at DateTimePicker.WmReflectCommand(Message& m) at DateTimePicker.WndProc(Message& m) at ControlNativeWindow.OnMessage(Message& m) at ControlNativeWindow.WndProc(Message& m) at NativeWindow.DebuggableCallback(IntPtr hWnd, _ Int32 msg, IntPtr wparam, IntPtr lparam) at UnsafeNativeMethods.SendMessage(HandleRef hWnd, _ Int32 msg, IntPtr wParam, IntPtr lParam) at Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam) at Control.ReflectMessageInternal(IntPtr hWnd, Message& m) at Control.WmNotify(Message& m) at Control.WndProc(Message& m) at ScrollableControl.WndProc(Message& m) at ContainerControl.WndProc(Message& m) at Form.WndProc(Message& m) at ControlNativeWindow.OnMessage(Message& m) at ControlNativeWindow.WndProc(Message& m) at NativeWindow.DebuggableCallback(IntPtr hWnd, _ Int32 msg, IntPtr wparam, IntPtr lparam) ← ScrollBarを押してます。 at UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, _ IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam) at NativeWindow.DefWndProc(Message& m) 〜略〜 この上から1つの操作(マウスダウン)で処理が連続しています。 at ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at Application.Run(Form mainForm) at Form1.Main() D:\〜略〜 ミニマムコード・・・了解です。コード自体は先述のコード例でほぼ全てなんですが、 サンプルを起こしてソース全文を上手く載せられるようにします。 | ||||||||
|
投稿日時: 2006-04-07 17:26
以下、サンプルコード全文です。MonthCalendarでも発生するので変更しました。
Public Class Form1 Inherits System.Windows.Forms.Form #Region " Windows フォーム デザイナで生成されたコード " Public Sub New() MyBase.New() InitializeComponent() End Sub 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 Private components As System.ComponentModel.IContainer Friend WithEvents MonthCalendar1 As System.Windows.Forms.MonthCalendar <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() Me.MonthCalendar1 = New System.Windows.Forms.MonthCalendar Me.SuspendLayout() ' 'MonthCalendar1 ' Me.MonthCalendar1.Location = New System.Drawing.Point(64, 40) Me.MonthCalendar1.Name = "MonthCalendar1" Me.MonthCalendar1.TabIndex = 0 ' 'Form1 ' Me.AutoScaleBaseSize = New System.Drawing.Size(5, 12) Me.ClientSize = New System.Drawing.Size(292, 273) Me.Controls.Add(Me.MonthCalendar1) Me.Name = "Form1" Me.Text = "Form1" Me.ResumeLayout(False) End Sub #End Region Public count As Integer Private Sub MonthCalendar1_DateChanged _ (ByVal sender As System.Object, _ ByVal e As System.Windows.Forms.DateRangeEventArgs) _ Handles MonthCalendar1.DateChanged Try count += 1 Trace.WriteLine("Count=" & count) MessageBox.Show("Count=" & count, "Test", MessageBoxButtons.OK) Catch ex As Exception Trace.Fail(ex.Message) End Try End Sub End Class 色々な操作をすると、そのうちループに入って例外エラーが発生します。 私が大きな勘違いをしているかもしれません。御指摘頂けると助かります。 既成のカレンダーを使用するのを辞めようかとも考えています。 | ||||||||
|
投稿日時: 2006-04-07 17:51
なるほど、再現しました。
どうやらフラグを設けても月が遷移するのが止まらないということは、 MessageBox が表示されたタイミングで、[月移動] ボタンを離したことにされてないようです。
MessageBox の代わりに Form を表示しても再現するんですね。 MessageBox を使うのをやめるしかなさそうですね。 ErrorProvider とか別のものを使った方が良さそうですね。 _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||||||
|
投稿日時: 2006-04-07 21:18
まずは設計の見直し、ですかね。
ValueChanged イベントは、ユーザが値を更新している最中に発生します。分岐処理が何をしているかわからないので、例えば、 「 他のところにある“前半・後半フラグ”によって、設定できる月を 1〜6 月、7〜12 月に制限する。 制限に違反する入力がある場合、警告メッセージを出す。 」 としましょう。すると、フラグが“後半”を意味しているとき、12 月を表すために "1" を入力したところで、制限違反を示す警告が現れることになります。 他に、10 月を 11 月に修正しようとして、"0" を削除しても、制限違反になります。 これでは、明らかにユーザビリティが悪いです。 他のイベントに処理を移すことが出来ないか、考えましょう。 〆 written by Jitta@わんくま同盟 on 2006/04/07 □ Microsoft MVP for Visual Developer ASP/ASP.NET October, 2005 - September, 2006 |