プロが教える店舗&オフィスのセキュリティ対策術

実行時にコントロールのイベントの登録/解除を、イベントハンドラのメソッドをあらかじめ知っていないロジックから実施する方法


通常、実行時にコントロールにイベントの登録/解除
を行う際は。

AddHandler 対象コントロール.イベント名, AddressOf メソッド
RemoveHandler 対象コントロール.イベント名, AddressOf メソッド



AddHandler 対象コントロール.イベント名, メソッドのデリゲート型
RemoveHandler 対象コントロール.イベント名, メソッドのデリゲート型

を行うと思います。
しかし、この方法では、これを実施するロジックが
AddressOf メソッド

メソッドのデリゲート型
を知っていなければなりません。

そうではなく、それをあらかじめ、知っていなくても

対象コントロール から
AddressOf メソッド

メソッドのデリゲート型
に該当するオブジェクトを取得するなどして、
実施できる方法を教えてください。

言語は、.NET系であれば。。
VB.NET, C#, C++のいづれかでもよいです。
できさえすればよいです。
J#とか、Delphi.NETとかマイナーなのは、厳しいです。
なお、C++でもしできるのであれば。
2003のマネージC++と、
2005のC++/CLIの両方について知りたいです。

以上、よろしくお願いします。

A 回答 (4件)

う~ん。

何だか厳しいような気がしてきました・・・

このソースの全容を理解しないままの回答なので、間違いがあるかもしれませんので、疑いながら読んでください。

EventHandlerListについて、MSDNライブラリを読んでみると、
( http://msdn2.microsoft.com/ja-JP/library/8843a9c … )
イベントを大量にもっているクラスの場合、ハンドルされない可能性の高いイベントをひとつずつ変数で管理するのはメモリの無駄だから用意されている機構のようで、これのキーになっているオブジェクトは一意でさえあれば何でも良いように見えますね・・・

それで、このキーを特定するのが最初のソースの
private static FieldInfo GetEventIDField(Type objType, string eventName)
の中身だと思うんですが、取得するフィールド名を "Event"+eventName と決め打ちしてしまっているので、.Net Frameworkに標準のクラスはこの命名規則に従っていそうな雰囲気ではありますが、これを守る義務のないサードパーティ製のものだとダメですよね、多分。

時間を無駄にさせてしまいまして申し訳ありませんが、どうも何か別な手段が必要そうです・・・
    • good
    • 0

試していませんが、おっしゃる内容に近いのではないかというをやっているコードがあります。


http://www.technewsgroups.net/group/microsoft.pu …
中身を良く読んでいないので、これでうまくいくかわかりませんし、サードパーティ製のコンポーネントの場合、同じ方法が使えるのかも不明です。
ひょっとすると、System.Reflection名前空間を調べてみると良い方法が見つかるかもしれませんよ。

参考URL:http://www.technewsgroups.net/group/microsoft.pu …
    • good
    • 0
この回答へのお礼

回答ありがとうございます。さっそく、
↑のサイトのソースを参考にして、
EventDescriptorCollection events = TypeDescriptor.GetEvents(myComponent);
foreach (System.ComponentModel.EventDescriptor myEvent in events)
{
のループの中で
EventDescriptorのNameプロパティと
自分が現在、注目しているイベントの名前
("Click"などの文字列)とを比較すると、
自分が注目している該当イベントの
EventHandlerListオブジェクトジェクトの取得まで
できるところまでこぎつけました。

EventHandlerListのVBでいうところのデフォルトプロパティとして定義されたitemプロパティ、C#でいうところのにインデクサに相当するものは、
object keyを引数にとり、
System.Delegateを取得できるようです。

なので、このSystem.Delegateを取得できれば、
AddHandlerやRemoveHandlerのカンマの後ろにくる
披演算子として使えます。
ところが、このobject keyに何を与えても
Nothingしか帰って来ない、いったい何をキーとして
要求するかの仕様がいまいちわからないです。
メソッド名や、イベント名やクラス名などおもいあたるものをいろいろ与えて試してもNothingしかかえってこないです。
しょうがないのでEventHandlerListオブジェクトそのものをforeach構文のinの後ろにもっていって、
System.Delegate型で取得しながら、ループをまわして、AddHandlerなり、RemoveHandlerをやってやろうと
おもいましたが、EventHandlerListオブジェクトが
コレクションではないという理由でコンパイルエラーになってしまいました。
○○Listって名前からして、いけそうに見えたのですが残念です。
EventHandlerListオブジェクトのヘルプを見てみましたが、インデクサのobject keyになにを入れたら、
System.Delegate型を取得できるか?の仕様や?
System.Delegate型のコレクションをあらわす、プロパティやそれを取得できるメソッドといったメンバが見当たらず。
お手上げになってしまいました。・・・・・

お礼日時:2006/09/04 22:05

お世話になります。



AddHandler 及び RemoveHandler
で追加したり削除したりする対象のイベントを
知らないでやる事は出来ないと思います。

私も前に、サードパーティ製品を使って
どうにもそのコントロールの挙動が
望むものと違ったとき、
そのコントロールを継承したクラスを作って
挙動を変えたいイベントを突き詰めて
オーバーライドして逃げた記憶があります。

> とりあえずは、グローバル領域にフラグをたてて、
> メソッドの先頭で、フラグをたてて、後処理でおろす
この方法と似ていますが、
その自身で拡張したクラスに独自プロパティを設けて
そのプロパティの値を見て
オーバーライドしたイベントハンドラ内で
何かする、という方法です。
    • good
    • 0

お世話になります。



> そうではなく、それをあらかじめ、知っていなくても
> 対象コントロール から
> AddressOf メソッド
> や
> メソッドのデリゲート型
> に該当するオブジェクトを取得するなどして、
> 実施できる方法を教えてください。

それだったら、普通に、そのオブジェクトの振る舞いとして、
AddressOf 等で定義付けるのではなくて
初めから実装しておけばよいのでは?

その該当クラスの該当メソッドが
外部クラスから操作することありきでやるのであれば
インターフェースや抽象クラスを使った上で
そのような実装を行うような設計を
した方がよさそうな感じはしますけれども。

この回答への補足

回答ありがとうございます。
説明不足でしたので補足します。

>その該当クラスの該当メソッドが
>外部クラスから操作することありきでやるのであれば
>インターフェースや抽象クラスを使った上で
>そのような実装を行うような設計を
>した方がよさそうな感じはしますけれども

イベントの設定/解除を行いたい対象オブジェクトが
自作クラスのオブジェクトであればもちろんそのように致します。

外部のサードパーティー製のユーザコントロール(DLLとNDoc提供のみ)のオブジェクトを使っている部分のプログラムのお話でして、そのユーザコントロール
のあるプロパティ値を変更した時、意図しないイベントが走ってしまいます。
通常は、ユーザが画面操作を行った時に変更される
プロパティなのですが、その際には、イベント処理が走ります。
問題は、プログラムからそのプロパティを変更した時にイベントが走ってしまう。
のを回避したかったんです。

実は、現在開発しているシステムの一部は、
多言語(.NET系ではない)で作られた旧システムの
ソースをコンバートすることで作ってる部分があります。
旧システムで使ってるコントロールと近いサードパーティー製のユーザコントロールを使っていたのですが。
旧システムの言語仕様では、↑のプロパティに該当するプロパティをプログラムから変更した時に、
イベントが発生しない仕様になっています。
旧システムのコントロールを使い勝手と、
新システムのコントロールの使い勝手が異なるため、
その違いを吸収したり、言語間の仕様の違いを吸収するために、プロパティの値の設定や、解除に対応する
ユーティリティメソッドを作って、その中で、
出てきた問題などを吸収して、開発をすすめていました。
そして、今回のイベントが発生する/しないの
問題をそのメソッドの中で吸収したいのですが
そのメソッドの中には、コントロールと、設定値
の2つの引数しかとるようになっていないです。
実際に該当する画面で、該当インスタンスに関連づいたコントロールのメソッドを知ることができないんです。
じゃー、そのメソッドがそれを引数にとればいいじゃないですか?
といわれそうですが。。。
プログラムのコードからその種類のプロパティを
設定/解除しているコードは大量にあります。
また、今後も似たような問題はでるかもしれないです。

メソッドの中は、
イベントの解除をおこない、
プロパティ値の設定をおこない、
イベントをまた、元に戻す。
ようにしたいです。

ある程度のモジュール数を作らないと、動作ができない物理的な事情や、工数の問題から旧システムからの移行部分に関してはこのような手法で、作ってます。
なので、既に、この問題を解決しなければならない多くのコードに、対して、引数追加はせず、完全にイベントハンドラのメソッドを知らないロジックから
できる方法が知りたいんです。

とりあえずは、グローバル領域にフラグをたてて、
メソッドの先頭で、フラグをたてて、後処理でおろす

イベントハンドラ側の先頭ではフラグがたっていれば
なにもしない
というロジックをいれることで回避できるみたいです。
プログラムのコードからプロパティ値を設定している
コードよりも、イベントハンドラの定義の数のほうが
少ないのでその方法で逃げれそうですが。
本当は、それもしたくないんです。

そういう経緯があって今回の質問をしました。

補足日時:2006/08/28 00:27
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!