トップ回答者
MDIの子フォームの再表示処理について

質問
-
MDIの子フォームを再表示(Visible=False後にVisible=Trueを実行)した際の動作について分からない点があるので、
解決にご協力していただけると幸いです。
MDIの子フォームを再表示した際に、その子フォームに配置してある全コントロールのLoadイベント(他のイベントも?)が
発生しているようなのですが、これはMDIの仕様なのでしょうか?
例えば以下のようなコードを例に取ります。
----------------------------------------------------------------------------------------------------
【Form1(起動Form)】 配置コントロール : ButtonA
Public Class Form1
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.IsMdiContainer = TrueDim a As New Form2
a.MdiParent = Me
a.Show()
End SubPrivate Sub ButtonA_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonA.Click
Me.MdiChildren(0).Visible = Not Me.MdiChildren(0).VisibleEnd Sub
End Class
【Form2】 配置コントロール : UserControlB
Public Class Form2
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.UserControlB.BackColor = Color.Red
End SubEnd Class
【UserControlB】 配置コントロール : 無し
Public Class UserControlB
Private Sub UserControlB_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.BackColor = Color.Blue
End Sub
End Class
----------------------------------------------------------------------------------------------------例のコードを実行すると、起動時にMDIの子フォーム「Form2」に配置されている「UserControlB」の背景色が「赤色」で
表示されます。
しかし、MDIの親フォーム「Form1」の「ButtonA」を二回押すことで、MDIの子フォーム「Form2」を再表示させると、
「UserControlB」のLoadイベントが発生してしまい、背景色が「青色」に変わってしまいます。
通常のフォームでの再表示ではこのようなイベントは発生しない事は確認しました。
(コードは割愛しますが、起動フォームからモードレスフォームを開き、そのモードレスフォームに対して再表示を行った。)
実装として求めるのは、例のコードでいうと「再表示にもUserControlBの背景色は赤色のまま(再表示前の状態)で表示」です。
解決方法やアドバイス等、よろしくお願い致します。
回答
-
いわし さんからの引用 投稿時には「再表示にもUserControlBの背景色は赤色のまま(再表示前の状態)で表示」という、 UserControlの動作に限ったような書き方をしてしまいました。
UserControl に限った内容ではなかったのですね。わかりました。
でも UserControl に限らず MDI の子フォームを表示するたびに、子フォーム内の全てのコントロールのハンドルが再作成されているようです。これが原因で DataGridView に設定した行の背景色が未設定状態になってしまうようです。
DataGridView のハンドルが再作成されると いわし さんもお気づきのように再度バインドし直しているようです。
その時に背景色の設定がクリアされてしまっているようです。
なので私が提案する解決策としましては、データバインディングが完了した後に背景色を設定すればいいと思います。
幸いデータバインディングが完了したイベントが DataBindingComplete イベントとして用意されています。
そのイベント処理で背景色を設定すれば MDI の子フォームを再表示しても背景色が失われる事がなくなると思います。
注意として一度のバインディングで DataBindingComplete イベントが何度も呼ばれるケースがあるかもしれません。
ただ私は DataGridView に関してあまり知識をもっていないため、他の適切な方法もあると思います。
いわし さんからの引用 これもMDIの仕様なのでしょうか? MDI の仕様と DataGridView の仕様が絡み合って発生している感じのようですね。
どうも MDI の子フォームを再表示した時に全てのコントロール(子フォームも含めて)のハンドルが再作成されるのが、問題のような気もするのですが、致し方ない感じです。
すべての返信
-
いわし さん、こんにちは
ダッチです。
この動きは仕様のようです。
Web 上にある MSDN ライブラリに記載されていました。
ローカルの MSDN には記載されていない可能性があります。(私の(何月のかは忘れました)には記載されていませんでした)
UserControl.Load イベント
http://msdn2.microsoft.com/ja-jp/library/system.windows.forms.usercontrol.load.aspx
一部を引用します。
メモ :
UserControl が MDI 子フォームの一部である場合、子フォームが表示されるたびに Load イベントが発生します。この場合、Load イベント ハンドラを設定するのではなく、一度限りの初期化コードを UserControl に用意する必要があります。
注意 :
UserControl のハンドルを作成すると、Load イベントが発生します。場合によっては、これが原因で Load イベントが複数回発生することがあります。たとえば、Load イベントが UserControl の読み込み時に発生し、さらにハンドルの作成時に発生します (ハンドルを再作成する方法の 1 つは、RecreateHandle メソッドを呼び出すことです)。Load イベントが複数回発生する場合に備えて、Load イベント ハンドラの代わりに、一度限りの初期化コードを UserControl コンストラクタに用意する必要があります。注意の部分に記載されているとおり、解決するためには UserControl のコンストラクタに Load イベントで行っている処理を記載すればいいと思います。
-
ダッチさん、回答ありがとうございました。
なるほど。MDI子フォーム上のUserControlはこの様な動きをするのですね。
勉強になりました。
ただ、求めていた実装に関して、投稿時のニュアンスが悪かったようです。
投稿時には「再表示にもUserControlBの背景色は赤色のまま(再表示前の状態)で表示」という、
UserControlの動作に限ったような書き方をしてしまいました。
投稿内容を変更するようで申し訳ないのですが、改めて具体的な問題について解決の協力をお願いします。
----------------------------------------------------------------------------------------------------
MDIの子フォームでDataTableにバインドした値を表示するDataGridViewを表示しています。
このDataGridViewは表示するデータの内容に応じて、行毎に背景色を設定しています。
(DataGridViewRow.DefaultCellStyle.BackColorを設定。)
このDataGridViewの背景色がMDI子フォームの再表示時にクリアされてしまい、困っています。
デバックしたところ、バインドされたDataGridVirewの再表示時に一時的に
DataGridViewをクリアしているようなのです。(DataGridViewをクリア後にDataTableを再バインド?)
この辺りの実装が具体的にどうなっているのか、分かりません。
これもMDIの仕様なのでしょうか?
また、解決方法、代案等がありましたらアドバイスをお願いします。
-
いわし さんからの引用 投稿時には「再表示にもUserControlBの背景色は赤色のまま(再表示前の状態)で表示」という、 UserControlの動作に限ったような書き方をしてしまいました。
UserControl に限った内容ではなかったのですね。わかりました。
でも UserControl に限らず MDI の子フォームを表示するたびに、子フォーム内の全てのコントロールのハンドルが再作成されているようです。これが原因で DataGridView に設定した行の背景色が未設定状態になってしまうようです。
DataGridView のハンドルが再作成されると いわし さんもお気づきのように再度バインドし直しているようです。
その時に背景色の設定がクリアされてしまっているようです。
なので私が提案する解決策としましては、データバインディングが完了した後に背景色を設定すればいいと思います。
幸いデータバインディングが完了したイベントが DataBindingComplete イベントとして用意されています。
そのイベント処理で背景色を設定すれば MDI の子フォームを再表示しても背景色が失われる事がなくなると思います。
注意として一度のバインディングで DataBindingComplete イベントが何度も呼ばれるケースがあるかもしれません。
ただ私は DataGridView に関してあまり知識をもっていないため、他の適切な方法もあると思います。
いわし さんからの引用 これもMDIの仕様なのでしょうか? MDI の仕様と DataGridView の仕様が絡み合って発生している感じのようですね。
どうも MDI の子フォームを再表示した時に全てのコントロール(子フォームも含めて)のハンドルが再作成されるのが、問題のような気もするのですが、致し方ない感じです。