C# 从计时器中添加和删除事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/553942/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 07:56:03  来源:igfitidea点击:

C# adding and removing events from a timer

c#event-handling

提问by TK.

I am trying to add and remove events from a timer and I have the following code:

我正在尝试从计时器中添加和删除事件,我有以下代码:

Timer myTimer = new Timer(); // Windows.Forms Timer

public void addEvent(MyDelegate ev)
{
    myTimer.Tick += new EventHandler(ev);
}

public void removeEvent(MyDelegate ev)
{
    myTimer.Tick -= new EventHandler(ev);
}

I don't know If Im doing anything stupid in trying to add and remove delegates in this fashion, I am able to add delegates and get them to fire as expected. However, when I attempt to remove the events, they continue to fire on Timers Tick.

我不知道我是否在尝试以这种方式添加和删除委托时做了任何愚蠢的事情,我可以添加委托并让它们按预期触发。但是,当我尝试删除这些事件时,它们会继续触发 Timers Tick。

Can anyone see anything obviously wrong?

任何人都可以看到任何明显错误的东西吗?

采纳答案by atoumey

I believe that this code:

我相信这段代码:

myTimer.Tick -= new EventHandler(ev);

creates a new EventHandler object. It will never remove an existing EventHandler. To get the functionality you want, you should be passing in EventHandlers, not MyDelegates, to the add and remove methods:

创建一个新的 EventHandler 对象。它永远不会删除现有的 EventHandler。要获得您想要的功能,您应该将 EventHandlers 而不是 MyDelegates 传递给 add 和 remove 方法:

Timer myTimer = new Timer(); // Windows.Forms Timer

public void addEvent(EventHandler ev)
{
    myTimer.Tick += ev;
}

public void removeEvent(EventHandler ev)
{
    myTimer.Tick -= ev;
}

The calling code will have to keep track of the EventHandlers added, so that it can pass in the same EventHandler object when it is time to unsubscribe.

调用代码必须跟踪添加的 EventHandler,以便在取消订阅时传入相同的 EventHandler 对象。

回答by Factor Mystic

You should just be able to unsubscribe by referencing the name of your even handling method like so:

您应该能够通过引用您的偶数处理方法的名称来取消订阅,如下所示:

public void removeEvent(MyDelegate ev)
{
    myTimer.Tick -= ev as EventHandler;
}

回答by John Conrad

When adding and removing event handlers you are creating a new wrapper for your delegate each time. So in your remove method it's trying to remove a newEventHandler object that was never added as a listener to the event in the first place.

添加和删​​除事件处理程序时,您每次都为您的委托创建一个新的包装器。因此,在您的 remove 方法中,它试图删除一个新的EventHandler 对象,该对象从未首先添加为事件的侦听器。

If you want to keep using this type of setup, you could maybe stick your EventHandlers into a Dictionary. In the addEvent method, stick your newly created EventHandler into your dictionary, and in the removeEvent method, pull the EventHandler from the dictionary and remove that instead of instantiating a new one.

如果你想继续使用这种类型的设置,你可以将你的 EventHandlers 放入一个字典中。在 addEvent 方法中,将新创建的 EventHandler 粘贴到字典中,然后在 removeEvent 方法中,从字典中拉出 EventHandler 并将其删除,而不是实例化一个新的。

回答by Samuel

Your problem comes from having helper methods to do this. Without them, it works as expected, with them it does not know what to unhook.

您的问题来自于使用辅助方法来执行此操作。没有它们,它会按预期工作,有了它们,它不知道要解开什么。

To fix this, you will need to maintain a dictionary with the value being the EventHandler created in the hooking method so that you can remove that value later.

要解决此问题,您需要维护一个字典,其值是在挂钩方法中创建的 EventHandler,以便稍后可以删除该值。

Something like:

就像是:

var handlers = new Dictionary<MyDelegate, EventHandler>();

public void addEvent(MyDelegate ev)
{
    var handler = new EventHandler(ev);
    handlers.Add(ev, handler);
    myTimer.Tick += handler;
}

public void removeEvent(MyDelegate ev)
{
    myTimer.Tick -= handlers[ev];
}

You should add the appropriate checks if the element exists.

如果元素存在,您应该添加适当的检查。

You could also change your parameter type and it will work as expected.

您还可以更改参数类型,它会按预期工作。

public void addEvent(EventHandler ev)
{
    myTimer.Tick += ev;
}

public void removeEvent(EventHandler ev)
{
    myTimer.Tick -= ev;
}

addEvent(new EventHandler(...));
removeEvent(new EventHandler(...));

回答by Sam Meldrum

I don't know what you're doing wrong, but the usual approach I would use for Timers would be to subscribe to the Tickevent, and then disable the Timer when you don't want to receive the events, re-enabling when you do.

我不知道你做错了什么,但我用于 Timers 的通常方法是订阅Tick事件,然后在你不想接收事件时禁用 Timer,当你不想接收事件时重新启用做。

May not help you if you have more than one event handler hooked up to the event, but hopefully of some use.

如果您有多个事件处理程序连接到该事件,则可能无济于事,但希望有一些用处。

回答by Jeff Sternal

The initial code works fine, as long as the MyDelegate'ev' passed into addEventand removeEventis the same object instance (For example, if there is a class-level MyDelegatefield that contains the instance or if you follow the advice of several others here and keep the MyDelegateobject(s) in a Dictionary).

初始代码工作正常,只要MyDelegate' ev' 传入addEvent并且removeEvent是同一个对象实例(例如,如果有一个MyDelegate包含该实例的类级字段,或者如果您在这里遵循其他几个人的建议并保留该MyDelegate对象(s) 在字典中)。

I suspect the problem is that the code calling addEventand removeEventis passing new MyDelegateinstances pointing to some handler method, like so:

我怀疑问题在于代码调用addEventremoveEvent传递MyDelegate指向某个处理程序方法的新实例,如下所示:

addEvent(new MyDelegate(this.HandlerMethod));
// ... do some stuff
removeEvent(new MyDelegate(this.HandlerMethod));

In which case addEventand removeEventare creating EventHandlerdelegates which point to different method addresses even though those delegates in turn are pointing to the same method (this.HandlerMethod). This is because the EventHandlerdelegates that addand removecreate point to the MyDelegate.Invoke()method on different MyDelegateinstances rather than directly to the address of this.HandlerMethod.

在这种情况下,addEventandremoveEvent正在创建EventHandler指向不同方法地址的委托,即使这些委托又指向相同的方法 ( this.HandlerMethod)。这是因为和create的EventHandler委托指向不同实例上的方法,而不是直接指向.addremoveMyDelegate.Invoke()MyDelegatethis.HandlerMethod

回答by B. Clay Shannon

This should work:

这应该有效:

private void timer_Tick(object sender, EventArgs e)
{
    try
    {
        // Disallow re-entry
        timer.Tick -= timer_Tick;
        . . .
    }
    finally
    {
        timer.Tick += timer_Tick;
    }
}