- PR -

イベントの伝播

投稿者投稿内容
れい
ぬし
会議室デビュー日: 2005/11/01
投稿数: 346
投稿日時: 2008-05-16 15:15
うーむー。
私が短く書くとやっぱり伝わらないですねぇ。意味不明です。
わかりづらくてすみません>読んでる人全員。

私の思考過程をここに書くのはかなり大変ですが、
なるべく簡単に、書いてみます。
#私のやり方ですから、いいかどうかは知りません。

まず…。

データの包含関係とUIの包含関係が一致している範囲ではその階層にあわせて
コンポーネントを作っていきます。
これは問題ないですね。

件の仕様のように、データの包含関係とUIの包含関係が一致していない場合は、
複数のコンポーネントが密接に関わることになります。
避けたいところですが、仕様上しようがないのであれば、
それはその密接に関わったコンポーネント全体でひとつのコンポーネントとして、
密結合なコンポーネントを作成します。

今回はUserControlA、UserControl1、UserControl2、UserControl3が
密接に関わっていますから、
それらを包含するコンテナ(今回はForm)を密結合なコンポーネントとします。
密結合で、必ず「全体として一つ」として使いますから、
互いに参照を持ち合っても、なんら不具合はありません。
Formのコンストラクタもしくはイニシャライザで
内部を初期化する際に、互いの参照を持ち合います。
(子は親の参照のみを持つのが普通ですが。)

内部の通信は、その参照を使います。

イベントでもできますが、
パフォーマンス上もコーディングの単純さからも、
無駄ですので私は使いません。
イベントはコンポーネントが外部と通信するためにのみ使います。

ですので、
「Private Event」は私は滅多に使いませんし、
「Protected Event」もほぼ使いません。

また、コンポーネントを作るときに将来のことを考えて
いくつかのイベントは外部に公開しておきます。
UpdatedとかXXXStateChangedとか。

コンポーネントを作る際のベースのコンテナですが、
Formというのはコンテナであると同時に、
独立したトップレベルウィンドウになりうる特殊なコントロールですので、
ちょっと特殊な位置づけです。

そのときの状況に応じて、
・Formの上にそのまま作る
・UserControlやPanelの継承などで、独自定義のコントロールとして作る
の2者から選びます。
(後者は詳細には何通りかあるのはご存知の通り)

再利用する際に前者ならFormまるごと、
後者ならFormに載せるコントロールとして再利用することになります。
後者で作って、Formにそのコントロールしか載せない、というもよくやります。

そんな感じで作ります。
DOS時代とかWin16時代とか、遥か昔の癖も引きずってますので、
ベストではないと思いますが、指針程度にはなるかと。

以下、
indigo-xさんの書き込み (2008-05-16 12:52) と
otfさんの書き込み (2008-05-16 13:40) への返信がぐちゃぐちゃになりますが。


引用:

UserControl1からのEventですよね。。。


上で書いたように、イベントではなく参照を保持して、
その参照からInternal(friend)な関数・メソッドを呼びます。

引用:

UserControlAにイベントを定義しないということは
変更を他のインスタンスに通知する際
UserControlAからUserControl1,2,3またはFormに直接依存することになりますね


そうです。

引用:

それがFormにだったら循環依存になってしまうし、
UserControl1,2,3へだったら三つのクラスに依存することになるので
それは避けたいはずです。


上で書いたように、避けたいことなどありません。
互いに依存することはごく普通にあります。

互いに依存しないように作れるのなら、
それははじめから互いに依存しない独立したコンポーネントにできるということを意味します。
それができないので問題になってるわけですから、
あきらめて互いに密に依存したコンポーネントにします。

ただ、依存はなるべくツリー型にしておきます。
というか、自然とそうなるはずです。
そうならない場合、それはコンポーネントをさらに分解できることを意味します。
今回はUserControlA、UserControl1、UserControl2、UserControl3が
それぞれ親の参照を持てば十分に用は足りると思います。
親は当然全ての参照を持つことになります。

引用:

FormからCall UserControlA.再描画ですよね。。。。



そうです。
CallでもGoSubでも何でも。

引用:

ちょっとここがわからなかったんですが。。。(上と矛盾するようなしないような)
子コントロールが親コントロールのEventに参加するって事ですか?



引用:

ここでいう再利用というシチュエーションがよくわかりません。



よく推敲せずに適当に書いたら意味不明でした。
たいした意味はありません。
コンポーネントを作ったら、
内部の状態変化を通知するためのイベントを念のため作っておきますよ、
というだけです。

まぁこういったものは個々のスタイルですので、
絶対的に正しいものはありません。

参考になればと思い書いてみましたが…
正直私はこの辺の設計で他人のコードや説明が参考になったことはありません。

いろいろ試してレシピを増やせばそのうち悩まずに作れるようになるかと思います。
indigo-x
大ベテラン
会議室デビュー日: 2008/02/21
投稿数: 207
お住まい・勤務地: 太陽の塔近く
投稿日時: 2008-05-16 16:07
引用:

れいさんの書き込み (2008-05-16 15:15) より:

まぁこういったものは個々のスタイルですので、
絶対的に正しいものはありません。

参考になればと思い書いてみましたが…
正直私はこの辺の設計で他人のコードや説明が参考になったことはありません。

いろいろ試してレシピを増やせばそのうち悩まずに作れるようになるかと思います。


ありがとうございます。

絶対に正しいものはないですが、参考にはなっています。

そう言えばWndProcを使っても見たことあります
  WndProcなら制御ぽくなって良いのかもしれませんが。。。。
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2008-05-16 16:40

もう誰かが書いているかもしれませんが。。。

これは「ちゃんと Doc/View(あるいは MVC)すればよいパターン」だと思います。

UserControl にデータをカプセルするのではなく、Doc 役のクラスを作って、データはそこに集約することにします。

UserControl はどれも等しく、Doc 役のクラスが公開するメソッドを呼び出すことでデータを操作します。

UserControl は Model クラスが公開するイベントに接続して、データの更新を検知し、再描画等を行います。
indigo-x
大ベテラン
会議室デビュー日: 2008/02/21
投稿数: 207
お住まい・勤務地: 太陽の塔近く
投稿日時: 2008-05-16 17:30
引用:

渋木宏明(ひどり)さんの書き込み (2008-05-16 16:40) より:

これは「ちゃんと Doc/View(あるいは MVC)すればよいパターン」だと思います。



ありがとうございます。

モデル駆動と言う事ですね。

昔やった時もそんな感じで作ったのですが、
更新イベントの順番が登録順になるので
(複雑な画面の場合ですが)
多重にイベントが発生したような。。。。
  (特にChangedとかSelectedとかFocuse関係とか)

(書きながら思ったのですがプライオリティを付ければ
    いいのかもしれませんが。。。)
otf
ベテラン
会議室デビュー日: 2006/08/04
投稿数: 91
投稿日時: 2008-05-16 17:33
「全体として一つ」っていう考えはあんまりよくないと思います。
ずっとその構造であることをどうやって保障しますか?
こういうのは案外変わりやすいものです。

コンポーネント全体で一つのコンポーネントだからといって
その構成要素は紛れもなくモジュール(ここでいうクラス)であって、
それぞれはできる限り疎結合になっているべきだと思います。
そのクラスがインナークラスにできるくらい小さなものであれば
循環参照もありかもしれません。(修正のコストが低いので)

問題なのはイベントのコストですが、
まずパフォーマンスはここでは考えるべきでないと思いますし
試してませんが問題になるレベルじゃないと思います。
コーディングについて考えてみると私はあまり差がないと思いました。
今後、通知の種類が増えたり通知する側が変更されたりするときに
それに応じた構造に変えればいいと思います。

今、1対1の関係でかつ通知の種類が一つなので
イベントではなくそのままデリゲートだけ保持するのもありかもしれません。

引用:

「Private Event」は私は滅多に使いませんし、
「Protected Event」もほぼ使いません。


これは私もほとんど使いません。
今回の例でも使わないと思います。

引用:

互いに依存することはごく普通にあります。


今回の例のような大きいクラス同士が循環依存になるとお互いの修正に敏感になるので
あまりいい構造とは思いません。

引用:

そう言えばWndProcを使っても見たことあります
  WndProcなら制御ぽくなって良いのかもしれませんが。。。。


あえて泥沼に足を突っ込むことは・・・。
Control.Invoke、Control.BeginInvokeで十分だと思います。

引用:

これは「ちゃんと Doc/View(あるいは MVC)すればよいパターン」だと思います。


それでできるところはそれがいいですね。
View内のクラス間で更新があるのでそれも問題だと思いますが。
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2008-05-16 17:55
引用:

View内のクラス間で更新があるのでそれも問題だと思いますが。



「子 View も親 View と同じ Doc を参照する」という手もあるし、「子 View は親 View がカプセルする、子 View 用の Doc を参照する」という手もあります。
otf
ベテラン
会議室デビュー日: 2006/08/04
投稿数: 91
投稿日時: 2008-05-16 19:37
引用:

渋木宏明(ひどり)さんの書き込み (2008-05-16 17:55) より:
引用:

View内のクラス間で更新があるのでそれも問題だと思いますが。



「子 View も親 View と同じ Doc を参照する」という手もあるし、「子 View は親 View がカプセルする、子 View 用の Doc を参照する」という手もあります。




うーん??
UserControlAの選択が変更されたときの通知のタイミングが問題だと思ったんですが
これもそれで解決できるんですか?
未記入
大ベテラン
会議室デビュー日: 2008/02/07
投稿数: 115
投稿日時: 2008-05-16 20:22
引用:

UserControlAの選択が変更されたときの通知のタイミングが問題だと思ったんですが


UserControlA (View) は Model を知っている。(参照を持っている。)
UserControlA…ツリーでしたっけ? これの選択行が変更されるというのは Model が変更されるということ、つまり、UserControlA が Model.SelectedItem とか何かを変更すればいい。

Model の変更にともなって、SelectionChanged のようなイベントを送出する。それを契機に、それぞれの View が自分の表示を更新したらよい。

スキルアップ/キャリアアップ(JOB@IT)