FolderBrowserDialogを連続してShowDialogすると2回目以降は最前面に表示されない。
質問
2008年7月3日木曜日 10:58
WinXP SP2とVB2008 ExpressEditionで開発しています。
ユーザーに2つのディレクトリを選択させるためにFolderBrowserDialogを使おうとしています。
最初のFolderBrowserDialogは最前面に表示されるのですが、その次のFolderBrowserDialogが
必ず他のウィンドウの背面に隠れてしまいます。
'1回目のディレクトリ選択
If Me.FolderBrowserDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
If Not Me.FolderBrowserDialog1.SelectedPath.Contains("C:\xxx") Then
System.Windows.Forms.MessageBox.Show("選択できるのは""C:\xxx""以下のディレクトリのみです。", "ディレクトリ選択エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
End If
Dim strDir As String
strDir = Me.FolderBrowserDialog1.SelectedPath
'2回目のディレクトリ選択
Me.FolderBrowserDialog1.Description = "●●●が入ったフォルダを選択して下さい。"
If Me.FolderBrowserDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim strDir2 As String
strDir2 = Me.FolderBrowserDialog1.SelectedPath
Else
'処理コード記述
End If
Else
'処理コード記述
End If
簡単ですが、上記のようなコードです。
FolderBrowserDialogのプロパティにそれらしいのを発見できませんでしたのでお知恵を拝借したく投稿させて頂きました。
よろしくお願いいたします。
すべての返信 (8)
2008年7月3日木曜日 11:27 ✅回答済み
モーダルが閉じた後に親ウィンドウがアクティブになるのは、ウィンドウメッセージが送られているからです。
プロシージャ実行中はそのウィンドウに送られたメッセージはキューに溜まり、プロシージャを抜けた時点で処理されます。
書かれたコードではプロシージャを抜けていませんので、親ウィンドウが非アクティブの状態でダイアログを表示することになります。
つまり、非アクティブということは他のウィンドウがアクティブです。
ダイアログは指定された親ウィンドウの一つ上層に表示されるだけですから、デスクトップの一番上に出てこないというわけです。
解決策としては、親ウィンドウをアクティブにすることです。
そしてそのタイミングでメッセージを強制的に処理させることです。
System.Windows.Forms.Application.DoEvents() を調べてください。
同じことが下記についても言えます。
Code Snippet
Private Sub Test()
Me.labelInfo.Text = "abc"
For Index As Integer = 0 To 100000
Next
End Sub
ラベルのテキストがプロシージャを抜けてから描画されるはずです。
2008年7月3日木曜日 12:52 ✅回答済み
基本的には同じことです。
そしてLoadであればウィンドウがいないので前面に持ってきようがありませんよね。
つまりダイアログに対して前面に来るように仕向けるしかありません。
そうなると最悪APIレベルのことをしなくてはいけません。
と書いておきながら、Vista+2005で試してみましたが現象は出ませんでした。
もしかしたらですがShowDialog(Me) で試してみてください。
親ウィンドウを指定していないことが原因かもしれません。
LoadではウィンドウハンドルがOSレベルでまだ作成されていないと推定され
Meを指定することによりウィンドウハンドルがその場で強制的に作成されるためと想像できます。
ただし、うまくいっても、OSの状況により現象が発生する可能性は捨てきれません。
関連して、かつ、別件ですが、
親フォームを見せたくない特別な理由をのぞいて
Shown イベントで処理することをおすすめします。
2008年7月3日木曜日 13:42 ✅回答済み
本筋とずれますが、気になったので書いておきます。
hone さんからの引用 | |
|
エラー表示した後、そのフォームは表示されますが、問題ないのでしょうか?
(Exit SubはLoadイベントの残りの処理を実行しないだけで、アプリケーションは終了されません。)
2008年7月3日木曜日 14:36 ✅回答済み
hone さんからの引用 | |
|
なおさら、Shown イベントに処理を移行してMe.Close()としたほうがよいでしょう。
コンストラクタやLoadでは自クラスの初期化に徹して、ユーザーにアクションさせるようなUI操作は好ましくありません。
イベントドリブンでの待機状態に入ったシグナルがShown イベント以降であり、それ以前は準備段階ととらえたほうがよいでしょう。
2008年7月3日木曜日 11:52
まどかさん。ご回答ありがとうございます。
少々、言葉足らずでしたが、記述したコードはFormのLoad中に書いています。
アプリケーションを起動する前に、ユーザーに2つのディレクトリを指定して欲しいのです。
「親ウィンドウが非アクティブの状態でダイアログを表示することになる」と、言う事は
親フォームのLoadが完了していないので、どうしてもやむを得ないのでしょうか…?
2008年7月3日木曜日 14:16
まどかさん、ありがとうございます。
すでに帰宅してしまったので、明日ShowDialog(Me) を試してまたご報告したいと思います。
2008年7月3日木曜日 14:20
Azuleanさん、ご指摘ありがとうございます。
投稿時のコピペミスです。
美しくないですが、Exit Subではなく、Endとして終了させています。
2008年7月4日金曜日 2:47
ShowDialog(Me)としたところ、2回目のダイアログもウィンドウの最前面に表示されました!
それから、これまでの処理を見直してLoad時には各種初期化のみを実施し、
ShownイベントにこれまでLoad内で行っていた処理をするようにソースの見直しをしました。
しばらく悩んでいた事が解決したので、今日は気分良く過ごせます。
レス下さった、Azuleanさん、まどかさん、本当にありがとうございました。