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在类级别添加a,初始化为,第一次执行后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
        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 回答
0

一个事件只有在它有订阅者时才会触发,所以你不能通过 删除委托-=,还是我误解了你想要做什么?

于 2012-12-10T22:42:25.180 回答