DOBON.NET DOBON.NETプログラミング掲示板過去ログ

MDI子フォームからMDI子フォームの操作

環境/言語:[OS : Windows XP Professional / .NET Framework : 2.0/C#]
分類:[.NET]

お世話になっております。

本日はMDI子フォームからMDI子フォームの操作について
お尋ねしたく、書き込み致しました。

今までは
「子フォームA」のプロパティに「子フォームB」、
「子フォームB」のプロパティに「子フォームA」を追加して
親フォームから子フォームのインスタンスを作成する時に
それぞれのプロパティにインスタンスを渡し、
「子フォームA」から「子フォームB」を操作する時は
「子フォームB」の入ったプロパティから直接操作していたのですが

一元管理の為、
親フォームに「子フォームA」、「子フォームB」プロパティを持たせて
「子フォームA」から「子フォームB」を操作する時は
親フォームの「子フォームB」プロパティを操作しようと思っているのですが

この方法で間違いはないでしょうか?
ご教授、お願いします。
> 「子フォームA」のプロパティに「子フォームB」、
> 「子フォームB」のプロパティに「子フォームA」を追加して

これは循環参照です。
場合によっては無限ループに陥ります。
やってはいけないということではなく、設計の誤りというより設計上ありえないということを理解してください。

クラスは閉じられた世界ですので通常依存性はありません。
そこへ依存性を持たせる場合、何が何に依存するかを明確にしなければなりません。

Public Class A
Private _B As B
End Class
Public Class B
End Class

AはBに依存しています。

> 一元管理の為、
> 親フォームに「子フォームA」、「子フォームB」プロパティを持たせて
> 「子フォームA」から「子フォームB」を操作する時は
> 親フォームの「子フォームB」プロパティを操作しようと思っているのですが

これも同じく循環参照です。

先に述べた依存性はそれぞれのクラスの性質によりますので、書かれた構成だけでは例を挙げることは出来ません。
■No20765に返信(こしあんさんの記事)
> お世話になっております。
>
> 一元管理の為、
> 親フォームに「子フォームA」、「子フォームB」プロパティを持たせて
> 「子フォームA」から「子フォームB」を操作する時は
> 親フォームの「子フォームB」プロパティを操作しようと思っているのですが
>
> この方法で間違いはないでしょうか?

私はその方法で正しいと思います。
構文的にも、デザイン的にも。

■No20766に返信(まどかさんの記事)
> これは循環参照です。
> 場合によっては無限ループに陥ります。
> やってはいけないということではなく、設計の誤りというより設計上ありえないということを理解してください。

えーと、読解力がないので私のほうかもしれませんが、
たぶん、まどかさんは何か勘違いしてると思います。

参照の持ち合いはよくやります。
それを循環参照とは言いませんし、
設計上、よくやるというか、
無いとかなり困ったことになると思います。

もちろん無限ループになることはありますが、
それは参照の持ち合いでなくても同じで、
プログラマがきちんと回避すべき問題です。
>まどかさん
設計上ありえない事だったんですね……。
勉強不足でした。

形としては
チャット機能を持ち合わせたゲームソフト。のようなものなのですが

親フォームで通信を管理していて、
受信したメッセージをメッセージ用子フォームに表示する。
メッセージ用子フォームに入力したメッセージを
親フォームの通信機能を使って相手側に送信する。

表示用子フォームで選択したデータを
詳細表示用子フォームで表示する。

操作用子フォームで押したボタンの結果を
メッセージ用子フォームに表示する
(もちろん、その表示は親フォームを経由して通信相手に表示されます。)

等の処理を考えています。

どういった形で実装するのが良いのでしょうか。
ご教授、よろしくお願いします。
#こしあんさん、ちょっと脱線します。

> たぶん、まどかさんは何か勘違いしてると思います。
>
> 参照の持ち合いはよくやります。
> それを循環参照とは言いませんし、
> 設計上、よくやるというか、
> 無いとかなり困ったことになると思います。

Public Class A
Private _B As B
End Class
Public Class B
Private _A As A
End Class

元記事からこのように認識したのですが、ありですか?
双方向で依存してはいけないのではないでしょうか?
確かにVB6のときは終了してもタスクマネージャに延々と居続けました。
そしてFrameworkになってFrameworkが循環参照に対応してそのようにならなくなったのも知っております。
考え方が古いというか、「あり」であることを私が知らないだけでしょうか?
あ、そういえば、Parentプロパティを否定することになりますね。。。
ぜんぜん思いつきませんでした。
そういう意味では「あり」ですね。
2007/10/16(Tue) 21:24:21 編集(投稿者)

>まどかさん

私の書き方が不味かったのかもしれませんが……

public class ParentForm : Form
{
private FormB _frmB;

public FormB frmB
{
get
{
return _frmB;
}
set
{
_frmB = value;
}
}

private FormA _frmA;

public FormA frmA
{
get
{
return _frmA;
}
set
{
_frmA = value;
}
}
}
---------------------------

この様に記述して、
親フォームから子フォームのインスタンス作成する時に
それぞれのプロパティにセットして

フォームBからフォームAを操作する時は
((ParentForm)this.Parent).frmA.Show();
と記述しよう。と思っていました
■No20769に返信(まどかさんの記事)
> Public Class A
> Private _B As B
> End Class
> Public Class B
> Private _A As A
> End Class
>
> 元記事からこのように認識したのですが、ありですか?

元記事の最初のパターンですよね?
勿論ありです。

当たり前すぎて不安になってきました。
私、会話のコンテキストがずれてますか?

> 確かにVB6のときは終了してもタスクマネージャに延々と居続けました。

VB6はもう覚えてませんが、
確かそれは破棄をきちんとしてないからではないですか?
参照の持ち合い自体が悪いわけではなかったはずです。

それにそれはGCの問題で。
GCがうまく行くようにコーディングするのはいいことですが、
そのせいでプログラムできなくなったら意味が無いです。
参照の持合を禁止したら、ほんとなにもできません。

C++、VB、Perlなど、凡そ参照のある言語全てで、
参照の持合をしてきました。

階層構造のある場合、親が子の、子が親の参照を持つのは当然です。
でないと、親が子を、子が親を見たい時に見れません。
System.Windows.Forms.Controlだって、ParentとControlsを持ってます。
内部でどんな実装になってるか知りませんが。
場合によっては兄弟姉妹の参照を持ってても不思議ではありません。

生成や破棄、検索、一覧取得などの場合に、
きちんと動作するようにするのはプログラマの責任です。

失敗の無いように、
子は持たないようにしたり、参照を一箇所に集めたり、
といったデザインにすることもありますが、
厳密に守ることはありません。
厳密に守ったら殆どなにも作れません。
■No20771に返信(こしあんさんの記事)
> フォームBからフォームAを操作する時は
> ((ParentForm)this.Parent).frmA.Show();
> と記述しよう。と思っていました

いいと思います。
FormAが一つなら、問題ない方法です。

privateなfieldに参照を入れて保持するのではなく、
プロパティ内部で毎回子フォームを検索する方法もあります。
もちろん遅くなりますが、
参照をfieldにいつ入れるのかといった問題がなくなります。
> この様に記述して、
> 親フォームから子フォームのインスタンス作成する時に
> それぞれのプロパティにセットして

いいんじゃないでしょうか。
インスタンスの管理者(作成者)がいて、その消滅と同時に消滅する、というのが自然です。

> フォームBからフォームAを操作する時は
> ((ParentForm)this.Parent).frmA.Show();
> と記述しよう。と思っていました

これがお互いに出てきますので先に書いたように、お互いに型を参照しあっています。
そういう観点からは変化はありませんね。
実際、ParentやContainerやOwner系の例もありますので、管理にさえ気をつければよいかと思います。
ただ、その必要が無ければ依存関係は一方向がよろしいかと思います。

#無理な例としては、アセンブリに相互参照とか。
> 当たり前すぎて不安になってきました。
> 私、会話のコンテキストがずれてますか?

混乱してましたが、冷静に考えると日常茶飯事でした。。。

Dim x As New A(Me)

まぁあえて言うなら、親が子に親を教える、という用途でしか使ってませんね。

このパターンと私が先に書いた例と異なる概念で捉えて回答してました。

>>確かにVB6のときは終了してもタスクマネージャに延々と居続けました。
>
> VB6はもう覚えてませんが、
> 確かそれは破棄をきちんとしてないからではないですか?
> 参照の持ち合い自体が悪いわけではなかったはずです。

いえ、事実です。
終了しないわけではなく、メモリが徐々に増え徐々に増減しながら長時間(分単位)後に終わるというものです。
ツリーを実装した際に子のParentプロパティに親自身を設定したところこの現象に遭遇しました。
で、MLで質問投げたら、某○.J.○先生に
「循環参照には対応していない。参照ではなくツリーノードを表す文字列などを設定するのがよい」
とご回答いただきました。
#循環参照云々については旧MSDNに記述があったと記憶しています。

> それにそれはGCの問題で。
> GCがうまく行くようにコーディングするのはいいことですが、
> そのせいでプログラムできなくなったら意味が無いです。
> 参照の持合を禁止したら、ほんとなにもできません。

これについては、先に書いたようにFrameworkでは解決されたということを知っております。
■No20775に返信(まどかさんの記事)
>>VB6はもう覚えてませんが、
>>確かそれは破棄をきちんとしてないからではないですか?
>>参照の持ち合い自体が悪いわけではなかったはずです。
>
> ツリーを実装した際に子のParentプロパティに親自身を設定したところこの現象に遭遇しました。

ありゃ。そうですか。

Formでなくて、普通のクラスですか?
終了時にParentとかChildにNothingを設定してもダメでしたか?

だとすると、VB6はかなり使えないですねぇ。
2007/10/16(Tue) 23:24:02 編集(投稿者)

>まどかさん
>れいさん

丁寧なご回答、ありがとうございます。
この方向で行って見ようと思います。
解決済み!
2007/10/17(Wed) 02:48:48 編集(投稿者)

■No20767に返信(れいさんの記事)
> 参照の持ち合いはよくやります。
> それを循環参照とは言いませんし、
> 設計上、よくやるというか、
> 無いとかなり困ったことになると思います。

私はこういうケースでも循環参照と呼んでいます.
参照の有向グラフを書いて自分自身に戻ってくれば,呼び名自体は循環参照でいいんじゃないでしょうか?
それを避けるべきかどうかはまた別問題として.

解決済みということですし,続きそうなら別のスレッドででも.
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板