none
ユーザーコントロールのイベントについて RRS feed

  • 質問

  • VisualStudio2005(VC)を使ってCLRのユーザーコントロール(System::Windows::Forms::UserControlから派生)を作成しています。

    独自のイベントを作成したのですが、コントロールを使用しているプログラム側(フォームアプリ等)で
    そのイベントハンドラが実装されているかどうかを、コントロール側で把握することは可能でしょうか。
    実装されていなければ、コントロール内部でデフォルトの動作を行いたいと考えています。

    C#の場合はイベント呼び出し時に

    public delegate void DelegateMyEvent();

    public event DelegateMyEvent MyEvent;
    private void button1_Click(object sender, EventArgs e)
    {
        if(MyEvent != null)
            MyEvent();
    }

    という形で確認できるようなのですがVCの場合は、使用するには、MyEvent がデータ メンバでなければ
    ならないというエラー(C3918)になってしまいます。

    2006年2月24日 11:15

回答

  • 実現するのなら、自分で delegate インスタンスを用意してカスタムイベントにするしかないんじゃないですかね。
    http://msdn2.microsoft.com/en-US/library/4b612y2s(vs.80).aspx
    UseControl は Component 派生クラスですし、Component::Events を使ってこんな感じ?

    public ref class Hoge : public UserControl {
    private :
      static initonly Object^ EventAnEvent = gcnew Object();
    public :
      event EventHandler^ AnEvent {
        void add(EventHandler^ handler) {
          UserControl::Events->AddHandler(EventAnEvent, handler);
        }
        void remove(EventHandler^ handler) {
          UserControl::Events->RemoveHandler(EventAnEvent, handler);
        }
        void raise(Object^ sender, EventArgs^ e) {
          EventHandler^ handler = dynamic_cast<EventHandler^>(UserControl::Events[EventAnEvent]);
          if (handler == nullptr)
            Console::WriteLine("event handler is null");
          else
            handler(sender, e);
        }
      }
      void RaiseAnEvent() {
        AnEvent(this, EventArgs::Empty);
      }
    };

    2006年2月24日 14:29

すべての返信

  • 実現するのなら、自分で delegate インスタンスを用意してカスタムイベントにするしかないんじゃないですかね。
    http://msdn2.microsoft.com/en-US/library/4b612y2s(vs.80).aspx
    UseControl は Component 派生クラスですし、Component::Events を使ってこんな感じ?

    public ref class Hoge : public UserControl {
    private :
      static initonly Object^ EventAnEvent = gcnew Object();
    public :
      event EventHandler^ AnEvent {
        void add(EventHandler^ handler) {
          UserControl::Events->AddHandler(EventAnEvent, handler);
        }
        void remove(EventHandler^ handler) {
          UserControl::Events->RemoveHandler(EventAnEvent, handler);
        }
        void raise(Object^ sender, EventArgs^ e) {
          EventHandler^ handler = dynamic_cast<EventHandler^>(UserControl::Events[EventAnEvent]);
          if (handler == nullptr)
            Console::WriteLine("event handler is null");
          else
            handler(sender, e);
        }
      }
      void RaiseAnEvent() {
        AnEvent(this, EventArgs::Empty);
      }
    };

    2006年2月24日 14:29
  • 迅速な回答、ありがとうございます。

    戻り値がvoid型のデリゲートを扱う場合は
    http://www.microsoft.com/japan/msdn/vs05/visualc/TransGuide.asp
    のデリゲートの箇所に書いてある方法もあるようですが、void型以外ではうまくいかない
    ようでした。Hongliangさんの方法ならどちらでもOKのようですが、イベント毎にこの記述
    をするのはちょっと厄介ですね。

    C#での作り直しを検討してみます。

    2006年2月25日 12:34
  • なんで,trivial events 方式の記述でもOKじゃないんでしょうね...
    2006年2月25日 13:44
  • VS2005ベータの頃に、このフォーラムのアメリカ版にあたる
    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3059&SiteID=1
    で同じように問題になり、バグレポートされたようですが、VC++コンパイラの
    プログラムマネージャの方が↓でバグではないと反論されてますね。
    http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=ac4f8e6b-c5eb-4ad0-9585-2fd0542a06aa
    2006年2月25日 15:59
  • 要するに,

    trivial events は,Delegateを一段抽象化(abstraction)したものなので,
    演算は,Add, Remove, Raise しか許さないようになっている
    ということのようですね...

    逆に言うと,

    Add, Remove, Raise の演算のみにDelegateを特化したというか,
    カプセル化してしまったものが,
    trivial events ということのようですね。
    だから,カプセル化された内部のDelegate自身にはアクセスさせないと...

    内部のDelegateは,イベント名とは別名になっている筈なので,
    コンパイル時に,イベント呼び出しところを
    その別名となっているデリゲート呼び出しに変更しないといけないので,
    面倒だった...という話だけじゃないのかなぁ... う~ん。
    (C# のコンパイラは,確か,そういう面倒なことをやってる筈だし)

    # ただ,「C# だとOKなのに~」という突っ込まれ方だと,ツライかもしれませんね。

    2006年2月25日 20:57
  • 重要なのは trivial でも non-trivial でもコンパイルする、という点だと思います。もし
     
    ref class R {
      event EventHandler ^ Event1;
      void Foo() {
        if (Event1 != nullptr) {
          ...
        }
      }
    };
     
    がコンパイルするなら、Event1 を non-trivial に変換した時もコンパイルしなくてはならない、という事だと思います。実際には Event1 を non-trivial にした場合は Event1 そのものではなく delegate をチェックしなくてはいけないので、上記のコードはコンパイルしません。
     
    2006年3月4日 2:40