2009-06-19 10 views
3

クラス間でイベントを渡すにはどうすればよいですか?C#イベントに沿ったバブリング/パススルー

私はそれがばかげていることを知っています(そしてそれです)が、私は過去の小さなことの間にこれを困惑しました。検索でも同様の質問が表示されなかったので、私はそれを提示すると考えました。ここで

が関与するオブジェクトです:

WinForm -> Speaker -> Tweeter 
        -> Woofer 

[スピーカー、ツイーター、ウーファー]すべては、単純な文字列メッセージを送る「SpeakToMe」イベントを宣言します。イベントが標準パターンを使用して宣言される:

public delegate void SpeakToMeHandler(object sender, SpeakToMeEventArgs e); 
public event SpeakToMeHandler SpeakToMe; 
protected virtual void OnSpeakToMe(string message) 
{ 
    if (SpeakToMe != null) SpeakToMe(this, new SpeakToMeEventArgs(DateTime.Now.ToString() + " - " + message)); 
} 

SpeakToMeEventArgsを文字列プロパティ(メッセージ)を含むのEventArgs &を継承する単純なクラスです。

これらのイベントはそれぞれ単独で機能します。たとえば、[Speaker、Tweeter、Woofer]のイベントを作成、登録、および起動するためのボタンをフォームに設定しました。それぞれが正しく戻ると報告します。

スピーカーが[Tweeter、Woofer]を作成し、そのイベントにサブスクライブするときに問題が発生します。

私は、[Tweeter、Woofer]が自分のイベントを発動し、スピーカーがそれを消費し、自分のイベントを発生させたいとします。私は、これは非常にまっすぐ進むべきであると思った:

void tweeter_SpeakToMe(object sender, SpeakToMeEventArgs e) 
{ 
    Console.Out.WriteLine("the tweeter is speaking: " + e.Message); 
    this.OnSpeakToMe("tweeter rockin' out [" + e.Message + "]"); 
} 

(スピーカーで)この機能によってステッピング、ます。Console.Out.WriteLineは動作します。 OnSpeakToMeを続行すると、デリゲートがnullであることが示されます。

スピーカーのSpeakToMeイベントは、フォームによって購読されています。イベントの代理人がnullにならないようにする必要があることを理解しました。

これは簡単なものだと確信していますが、何が欠けていますか?

Btw、なぜ私がこれを探しているのか不思議です。 [スピーカー、ツイーター、ウーファー]は、本当に長いデータ処理操作のための私のデモスタンドインです。フォームはこれらを同時に実行し、各クラスから進捗状況を更新する必要があります。

いつものように、すべてのヘルプは非常に高く評価されています!

更新:すべてのフィードバックありがとうございます。私は本当に助けに感謝します!私はいくつかの良いアイデア(@David Basarab & @Brian)と物事を構成する方法に関するいくつかのアイデアを取り上げました。再度、非常に感謝!

+0

を示唆しているあなたは、あなたのフォームがスピーカーのオブジェクトをサブスクライブする方法のコードスニペットを提供することはできますか? – LBushkin

答えて

4

あなたが基本的な意味で欲しかったことを理解すれば。ツィーターとウーファーにスピーカーが購読しているイベントを発してもらうことです。ツイーターによってトリガーさ

OnSpeakメッセージ= OnSpeakToMeHander Orginalメッセージ:ここ

は、この出力

OUTPUT

OnSpeakメッセージ= OnSpeakToMeHander Orginalメッセージを持っている私のコードです:ウーファーによって発砲された

class Program 
{ 

    static void Main(string[] args) 
    { 
     Console.Clear(); 

     try 
     { 
      Speaker speaker = new Speaker(); 
      speaker.speakerEvent += new SpeakToMeHandler(Program.OnSpeak); 

      // Cause events to be fied 
      speaker.Tweeter.CauseEvent(); 
      speaker.Woofer.CauseEvent(); 

     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Error: {0}", ex.Message); 
      Console.WriteLine("Stacktrace: {0}", ex.StackTrace); 
     } 
    } 

    public static void OnSpeak(object sendere, SpeakToMeEventArgs e) 
    { 
     Console.WriteLine("OnSpeak Message = {0}", e.Message); 
    } 

} 

public delegate void SpeakToMeHandler(object sender, SpeakToMeEventArgs e); 

public class SpeakToMeEventArgs : EventArgs 
{ 
    public string Message { get; set; } 
} 

public class Speaker 
{ 
    public event SpeakToMeHandler speakerEvent; 

    public Tweeter Tweeter { get; set; } 
    public Woofer Woofer { get; set; } 

    public void OnSpeakToMeHander(object sender, SpeakToMeEventArgs e) 
    { 
     if (this.speakerEvent != null) 
     { 
      SpeakToMeEventArgs args = new SpeakToMeEventArgs 
       { 
        Message = string.Format("OnSpeakToMeHander Orginal Message: {0}", e.Message) 
       }; 

      this.speakerEvent(this, args); 
     } 
    } 

    public Speaker() 
    { 
     this.Tweeter = new Tweeter(); 
     this.Woofer = new Woofer(); 

     Tweeter.tweeterEvent += new SpeakToMeHandler(this.OnSpeakToMeHander); 
     Woofer.wooferEvent += new SpeakToMeHandler(this.OnSpeakToMeHander); 
    } 
} 

public class Tweeter 
{ 
    public event SpeakToMeHandler tweeterEvent; 

    public void CauseEvent() 
    { 
     SpeakToMeEventArgs args = new SpeakToMeEventArgs() 
      { 
       Message = "Fired By Tweeter" 
      }; 

     if (this.tweeterEvent != null) 
     { 
      this.tweeterEvent(this, args); 
     } 
    } 
} 

public class Woofer 
{ 
    public event SpeakToMeHandler wooferEvent; 

    public void CauseEvent() 
    { 
     SpeakToMeEventArgs args = new SpeakToMeEventArgs() 
      { 
       Message = "Fired By Woofer" 
      }; 

     if (this.wooferEvent != null) 
     { 
      this.wooferEvent(this, args); 
     } 
    } 
} 
+0

答えDavidさんありがとう。あなたの構造は、私がしていたものと非常に似ていました。主な違いは、イベントを発生させる統一された機能でした。 まだ私のエラーがあった場所で100%をピン止めすることはできませんでしたが、構造は魅力のように機能します。 私はその作品の1つを見逃していたに違いありません...それは当時のことの一つです。 もう一度おねがいします! – Mark

2

デリゲートがnullになる唯一の方法は、フォームが実際にイベントに登録されていない場合です。あなたはある時点で話し手の新しいインスタンスを作成しましたか? 1つのインスタンスをサブスクライブし、同じ変数を使用して新しいインスタンスを作成した場合、新しいインスタンスのイベントは連結されません。

0

イベントを渡すのではなく、イベントに追加のハンドラーを割り当てるのはなぜですか?あなたは1つの方法に限定されません。

//Handler class 
public class Speaker { 
    public delegate void HandleMessage(string message); 
    public event HandleMessage OnMessage; 
    public void SendMessage(string message) { 
     if (OnMessage != null) { OnMessage(message); } 
    } 
} 

//then used like... 
Speaker handler = new Speaker(); 
handler.OnMessage += (message) => { Console.WriteLine("Woofer: {0}", message); }; 
handler.OnMessage += (message) => { Console.WriteLine("Tweeter: {0}", message); }; 
handler.SendMessage("Test Message"); 
+0

私は信号の流れが反対の方向にあるという質問を理解したので、スピーカーはツイーターとウーファーを聴いていて、そのフォームはスピーカーに聞いています。たぶん私はそれを誤って読んだ... –

+0

おそらく、それはあなたがまだ別のイベントを渡すのではなく、イベントハンドラが自分自身の世話をするようにあなたのコードを整理することができるようだ...確かに:) – Hugoware

+0

@HBossありがとう洞察のために間違いなく面白いアプローチ。残念ながら、フレドリクは正しいことがあります。この特定のケースでは、流れは反対方向です。 – Mark

1

長い形式のイベント宣言を使用すると、イベントを内部オブジェクトに渡すことができます。

public class Speaker 
{ 
    public Speaker() 
    { 
     this.MyTweeter = new Tweeter(); 
    } 

    public Tweeter MyTweeter { get; private set; } 

    public event SpeakToMeHandler SpeakToMe 
    { 
     add { MyTweeter.SpeakToMe += value; } 
     remove { MyTweeter.SpeakToMe -= value; } 
    } 
} 
+0

この解決策の1つの問題は、「送信者」パラメータがスピーカーではなく、ツイーターを後回しにしたときに、発信者が驚くことがあるということです。 – Andreas

4

Eric Lippertif (SpeakToMe != null)コードに対して警告しています。それは(つまり、あなたがイベントを削除することはありません場合)あなたのケースでは問題ではないかもしれませんが、あなたが代わりにこれを使用するのが習慣に取得する必要がありますC#6以降で

var tmp = SpeakToMe; 
if (tmp!=null) tmp(/*arguments*/); 

、代わりにこのterserコードを考えてみます。

SpeakToMe?.Invoke(e) 

後者のアプローチはon the MSDN

+0

ああ、そのリンクのおかげです。私は年齢のためにそれを探してきました。 –

+0

グッドチップ&読書、ありがとう! – Mark

+0

私はたぶん 'var tmp = SpeakToMe 'を使用しましたか?代理人{};代わりにtmp(/ * arguments * /);を実行します。 – Brian

関連する問題