- PR -

継承されたフォームに貼り付けられたコンポーネントの取得方法

投稿者投稿内容
ガルマ・ザビ
ベテラン
会議室デビュー日: 2007/06/07
投稿数: 55
お住まい・勤務地: ジオン公国
投稿日時: 2008-02-28 14:23
具体的にどういう動きを望まれているのかが、つかみきれていないので
質問の意図と食い違ってしまうかもしれませんが、お許しください。

親Formで、componentsフィールドをプロパティ公開

コード:
protected virtual System.ComponentModel.IContainer Components
{
    get
    {
        return this.components;
    }
}



子Formで、プロパティをオーバーライド。

コード:
protected override System.ComponentModel.IContainer Components
{
    get
    {
        return this.components;
    }
}



親FormのOnLoadでは、Componentプロパティを見て、Timerが入っていれば処理する。

コード:
protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    if (this.Components != null)
    {
         Timer childTimer = null;

	foreach (IComponent component in this.Components.Components)
	{
	    childTimer = component as Timer;

	    if (childTimer != null)
	    {
		〜 ここでタイマー処理 〜
	    }
         }
    }
}

まどか
ぬし
会議室デビュー日: 2005/09/06
投稿数: 372
お住まい・勤務地: ますのすし管区
投稿日時: 2008-02-28 14:52
引用:

子Form(継承したフォーム)に貼り付けられたタイマーを、
親Form(継承元フォーム)で一律に停止できればと思っています。



継承先独自の仕様で別のタイマが貼り付けられた場合はどうするんでしょうか?
#まさかNameプロパティで判断とかそんなんじゃ。。。

たぶん、どなたでも言われることは一緒だと思います。
・基底フォームにタイマを貼り付ける。
・継承先フォームで制御できるようにEnabled系のプロパティを基底フォーム用意しておく。
または、
・基底フォームで仕様上のタイマとしてのProtected変数なりを用意して、入っていれば決められた仕様で動作する、Nullなら何もおこなわない。


[ メッセージ編集済み 編集者: まどか 編集日時 2008-02-28 14:52 ]
味噌汁まんぼう
会議室デビュー日: 2008/02/27
投稿数: 14
投稿日時: 2008-02-28 15:43
☆くまっちさん
ご回答ありがとうございます。

なるほど、確かにこの方法だと、
継承したフォーム(派生フォーム)に貼り付けられたタイマーを、
継承元フォームで一律に処理できますね。ありがとうございます。

ただこの場合、継承したフォーム(派生フォーム)のクラス名が決まっていないと、
継承元フォームのコーディングができませんね…。

>派生したフォーム全てに、Timerが存在するならば
>派生元にTimerを用意しておくべきです。
たしかにそうですね。
ただ、派生したフォームに必ずタイマが存在するかどうかはわからない、
0個かもしれないし、1個かもしれないし、2個かもしれないし・・・、
それは派生したフォームを作成する人次第、という条件で考えているので、
派生元で一律に処理できる方法を考えているところです。

☆indigo-xさん
ご回答ありがとうございます。

>多分、要望は不定のtimerを見つけたいと言う意味だと思うので
そうなのです。
サンプルコードありがとうございます。
この方法だと不定のtimerは見つけられないですね…。

>通常では無理です(リフレクションしかないと思います)
そうですか…。
リフレクションも考えみたのですが、
継承したフォームがタイマをprivateなフィールドとして定義した場合、
継承元フォームで取得できないような気がしています。

☆渋木宏明さん
ご回答ありがとうございます。

>すべての派生クラスがタイマを実装するのなら
すべての派生クラスがタイマを実装するかどうかわからない、という条件で考えています。
派生クラスが実装するタイマは0個かもしれないし、1個かもしれないし、
2個かもしれないし・・・というわけです。

☆ガルマ・ザビさん
ご回答ありがとうございます。

>具体的にどういう動きを望まれているのかが、つかみきれていないので
説明が足らずすいません。

今回考えているのは、
例えば、この画面にある全てのタイマについて起動を禁止するか?というbooleanのプロパティがあるとして、
これが true であれば、全てのタイマの起動を禁止する、という仕様にしたいのです。

このプロパティは継承元フォームに作って、
継承元フォームのOnLoadメソッドにおいて、
同プロパティが true であれば、画面にある全てのタイマの Enabledプロパティ を false にする、
というような動きを考えています。
この、画面にある全てのタイマを調べる際に、
継承したフォームのタイマも取得する方法がわからず、困っているところです。

サンプルコードありがとうございます。
コーディングして動かしてみましたが、
残念ながら親Formでは子Formに貼り付けられたタイマは取得できませんでした。

☆まどかさん
ご回答ありがとうございます。

>継承先独自の仕様で別のタイマが貼り付けられた場合はどうするんでしょうか?
そうです。
このような場合にも対応できるような作りを考えているところです。

>・基底フォームで仕様上のタイマとしてのProtected変数なりを用意して、入っていれば決められた仕様で動作する、Nullなら何もおこなわない。
お書きいただいたことを考えてみました。

List<Timer>型のProtectedプロパティを継承元フォームに作成して、
継承したフォームでは、自分で貼り付けたタイマをそのプロパティに追加するという処理を、
コーディングする、という感じにすれば、
継承元フォームはそのプロパティにあるタイマについて処理すればよく、
私のやりたいことが実現できると思います。

ただ、この方法だと、継承したフォームを作成する人が、自らコーディングしなければならず、
これは避けたいと考えています。

例えば、継承したフォームにタイマを貼り付けた時点で、
上記のようなコーディングを自動的にしてくれるようなことができれば、理想的だと思います。

フォームのDesigner.csにボタンなどを貼り付けると、
this.Controls.Add( this.button1 );
のようなコードが自動的に生成されますが、
同じようなことができないか調べてみました。
が、残念ながら実現方法がわかりませんでした…。


[ メッセージ編集済み 編集者: 味噌汁まんぼう 編集日時 2008-02-28 15:49 ]
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2008-02-28 16:06
質問の意図がようやくわかりました。

継承クラス作成者にコーディングさせたくないというより
継承クラス作成者のコーディング忘れでTimerを取りこぼししたくない
という感じでしょうか。

そうなったらもう、リフレクションを使い取得するしか手はないと思います。

[追記]
System.Reflection.BindingFlags.NonPublicで非パブリックメンバも取得可能ですよ。

[ メッセージ編集済み 編集者: くまっち 編集日時 2008-02-28 16:10 ]
ガルマ・ザビ
ベテラン
会議室デビュー日: 2007/06/07
投稿数: 55
お住まい・勤務地: ジオン公国
投稿日時: 2008-02-28 16:21
そうですね、継承クラス作成者に全く意識させないようにしたいとなると、
リフレクションしか方法がないですね。

Framework的なものを作る上では、ある程度リフレクションを使うのは仕方ないとは思います。

ちなみに試してみたら、ちゃんと取得できました。
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2008-02-28 16:22
要望に沿わない事だと思うので、別レスとして書きます。(軽く聞き流してもOK)

私でしたら、基底クラスを抽象化し
タイマー起動可/不可を設定する純粋仮想関数を定義しますね。

派生クラスは、関数の実装を行わなければならないし
その可/不可に影響されたくないタイマーを持っている場合等も
容易に対応できるようになるので。
まどか
ぬし
会議室デビュー日: 2005/09/06
投稿数: 372
お住まい・勤務地: ますのすし管区
投稿日時: 2008-02-28 16:36
引用:

ただ、この方法だと、継承したフォームを作成する人が、自らコーディングしなければならず、
これは避けたいと考えています。



避ける、避けたいという問題ではないということを理解する必要があります。
利用する側は利用しようとしているものに従わなければならないのです。
解決に至らない根本のひとつは、基底フォームの仕様に、知ることが不可能な派生先の事柄を含めようとしていることです。
私は「基底フォームにProtectedな変数なりを用意して」と書きました。
これは「ここに入っていればxxxなことをします」という基底フォームで閉じられた仕様であり
まったく基底フォームの外側を意識していないし具体的なものも存在もしていません。
そういう意味では、ツールによるコード生成などの生産性向上策はあっても、クラスに埋め込むことはできません。

引用:

フォームのDesigner.csにボタンなどを貼り付けると、
this.Controls.Add( this.button1 );
のようなコードが自動的に生成されますが、
同じようなことができないか調べてみました。
が、残念ながら実現方法がわかりませんでした…。


これも同じことです。
Controlsは基底のControlクラスのメソッドです。
この引数の型は何でしょうか? Controlですよね。
つまり、Addメソッドの中でButton、TextBox・・・などの扱い(認識)はしていません。
というより先に書いたように「できない」ということです。

基底フォームは「処理するためのタイマ」という限定的なものを必要とします。
それを基底フォームで用意しない限り、外から教えてもらうという以外に方法はありません。

生産性などを考えれば自動化も重要なポイントかもしれません。
一方、設計では機能の範囲およびその役割は誰かということが大事です。
ただし、それを楽するためだけのために崩してはいけません。

#べき論ばかりで申し訳ないですが、最終的にくちゃくちゃになるとまずいと思いますので。
味噌汁まんぼう
会議室デビュー日: 2008/02/27
投稿数: 14
投稿日時: 2008-02-28 18:23
☆くまっちさん
ご回答ありがとうございます。

>System.Reflection.BindingFlags.NonPublicで非パブリックメンバも取得可能ですよ。
そうだったのですね…。失礼しました。

リフレクションを使って、作ってみたところ、思っていた動作が出来ました!!

コード:

// 基本フォーム
public partial class BasicForm : Form {
public BasicForm() {
InitializeComponent();
}

protected override void OnLoad( EventArgs e ) {
base.OnLoad( e );

// タイマのリストを取得
List<Timer> timers = new List<Timer>();
GetTimers( this, this.GetType() , timers );
}

// タイマのリストを取得
private void GetTimers( Form form , Type formType, List<Timer> timers ) {
// フォームが持つフィルードを取得
FieldInfo[] fieldInfos
= formType.GetFields( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
foreach( FieldInfo fieldInfo in fieldInfos ) {
// タイマの場合はリストに追加
if( fieldInfo.FieldType.Equals( typeof( Timer ) ) == true ) {
Timer timer = (Timer)fieldInfo.GetValue( form );
timers.Add( timer );
}
}
// 継承元が基本フォームでない場合は更に継承元を調べる
if( formType.BaseType.Equals( typeof( BasicForm ) ) == false ) {
GetTimers( form, formType.BaseType , timers );
}
}
}




>基底クラスを抽象化しタイマー起動可/不可を設定する純粋仮想関数を定義しますね。
>派生クラスは、関数の実装を行わなければならないし
確かにこれもいい案だと思います。
派生クラスで絶対実装しなければいけなければ従わざるをえないですしね。

いろいろとありがとうございました。

☆ガルマ・ザビさん
ご回答ありがとうございます。

>そうですね、継承クラス作成者に全く意識させないようにしたいとなると、
>リフレクションしか方法がないですね。
リフレクションを使って実現することが出来ました。
どうもありがとうございました。

☆まどかさん
ご回答ありがとうございます。

>解決に至らない根本のひとつは、基底フォームの仕様に、知ることが不可能な派生先の事柄を含めようとしていることです。
おっしゃるとおりです。
Controlsプロパティに対するまどかさんのご指摘、確かにその通りです。
今回のようにリフレクションを使ってやることは、
私としてもいささか強引な感じはしております。

まどかさんのご指摘は設計の基礎として参考にさせていただきます。
ご教授ありがとうございました。


[ メッセージ編集済み 編集者: 味噌汁まんぼう 編集日時 2008-02-28 18:29 ]

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