2
public event EventHandler ConstructDesign;
public DataGridView dataGrid = new DataGridView();
public FooClass(Action action) {
    ConstructDesign+=action;
    dataGrid.DataBindingComplete+=ConstructDesign;
}

public void Launch() {
    ConstructDesign(null, new EventArgs());
}

//IN A COMPLETELY DIFFERENT CLASS:
public void Main(string[] args) {
    var launcher = new FooClass(Fire);
    launcher.Launch();
}

public void Fire(object sender, EventHandlerArgs args...) {
    Console.WriteLine("Fired");
    //and after the first fire, action will be removed from the `ConstructDesign`.
}

したがって、基本的にここで達成しようとしているのは、次の方法です。Actionコードを介して手動で追加されConstructDesign、起動すると、イベントハンドラーから自分自身を削除しますConstructDesign。何か案は?

4

5 に答える 5

1

イベントの発生を停止できるとは思いませんが、イベント内のコードの実行を停止することはできます。本当に簡単static boolです。クラスレベルでを追加し、初期化して、最初の実行後にtrueに設定します。falseのイベントハンドラー内にコードをラップしますif (firstExecution) {//actions I only want executed the first time the event fires}

于 2012-12-10T22:38:53.540 に答える
1

どこにも登録していないので、なぜクラスにイベントがあるのか​​わかりません。代わりに、渡されたアクションを呼び出します。

Action _action;

public FooClass(Action action) 
{
    _action = action;
}

public void Launch() 
{
    if (_action == null)
        return;

     _action();
     _action = null;        
}
于 2012-12-10T22:57:28.853 に答える
1

最初に使用した後、イベントの購読を解除する良い方法が見つかりませんでした。(確かにリフレクションを多用するアプローチを使用することもできますが、リファクタリングによってイベントの名前が変更された場合にコンパイラーが文句を言うことはないと思います)。

これはデリゲートのみを使用するものであるため、コンパイラーは引き続き適切に機能します。必要なほど軽量ではないかもしれませんが、自分で啓蒙に挑戦したので、シェアしたいと思いました。

MyEvent += SingleUseEventHandler<AssemblyLoadEventArgs, AssemblyLoadEventHandler>
   .Create(This_MyEventOccurred);

ここで魔法が定義されている場所:

public class SingleUseEventHandler<TArgs,THandler>
  where TArgs : EventArgs
{
  public static THandler Create(EventHandler<TArgs> handler)
  {
     var helper = new SingleUseEventHandler<TArgs, THandler>(handler);
     EventHandler<TArgs> h = helper.InvokeIfFirstTime;
     return (THandler)(object)Delegate.CreateDelegate(typeof(THandler), h.Target, h.Method);
  }

  public void InvokeIfFirstTime(object sender, TArgs args)
  {
     if (!raised)
     {
        raised = true;
        handler(sender, args);
     }
  }

  public SingleUseEventHandler(EventHandler<TArgs> handler)
  {
     this.handler = handler;
  }

  bool raised;
  readonly EventHandler<TArgs> handler;
}

もちろん、C#はデリゲートの種類を推測しないため、明示的に指定する必要があります。

イベントの定義がEventHandlerの場合、代わりにこれを使用できます。

MyEvent += SingleUseEventHandler<SomeEventArgs>.Create(SomeHandlerMethod);


public static class SingleUseEventHandler<TArgs>
  where TArgs : EventArgs
{
  public static EventHandler<TArgs> Create(EventHandler<TArgs> handler)
  {
     var helper = new SingleUseEventHandler<TArgs, EventHandler<TArgs>>(handler);
     return helper.InvokeIfFirstTime;
  }
}

プログラムの例を次に示します。

class Program
{
  static event AssemblyLoadEventHandler MyEvent;
  static int callCount;
  static void Main(string[] args)
  {
     MyEvent += SingleUseEventHandler<AssemblyLoadEventArgs, AssemblyLoadEventHandler>
        .Create(Load);

     foreach(var assembly in AppDomain.CurrentDomain.GetAssemblies())
     {
        Console.WriteLine("Raising event for " + assembly.GetName().Name);
        MyEvent(null, new AssemblyLoadEventArgs(assembly));
     }
  }

  static void Load(object sender, AssemblyLoadEventArgs eventArgs)
  {
     Console.WriteLine(++callCount);
  }
}
于 2012-12-11T16:08:49.837 に答える
0

イベントはサブスクライバーがいる場合にのみ発生するので、を介してデリゲートを削除することはできませんか-=、それとも私はあなたが何をしたいのか誤解していますか?

于 2012-12-10T22:42:25.180 に答える
0
        public class FooEvents {
            public event EventHandler ConstructDesign;
            public DataGridView dataGrid = new DataGridView();
            public FooEvents(Action action) {
                ConstructDesign+=action;
                dataGrid.DataBindingComplete+=ConstructDesign;
                dataGrid.DataBindingComplete+=RemoveSubscribtion;
            }

            public void Launch() {
                ConstructDesign(this, new EventArgs()); //passes FooEvent and fires.
            }

            private void RemoveSubscribtion(object sender, EventArgs args) {
                 dataGrid.DataBindingComplete-=ConstructDesign;
                 dataGrid.DataBindingComplete-=RemoveSubscribtion;
            }

       public Main {
            public void Main(string[] args) {
                var launcher = new FooClass(Fire);
                launcher.Launch();
            }

            public void Fire(object sender, EventHandlerArgs args) {
                Console.WriteLine("Fired");
            }
       }
于 2012-12-10T23:27:14.580 に答える