C # добавление и удаление событий из таймера - PullRequest
8 голосов
/ 16 февраля 2009

Я пытаюсь добавить и удалить события из таймера, и у меня есть следующий код:

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);
}

Я не знаю, если я делаю какие-то глупости, пытаясь добавить и удалить делегатов таким образом, я могу добавить делегатов и заставить их работать так, как ожидалось. Однако, когда я пытаюсь удалить события, они продолжают срабатывать по таймеру.

Кто-нибудь может увидеть что-то явно не так?

Ответы [ 7 ]

8 голосов
/ 16 февраля 2009

Я считаю, что этот код:

myTimer.Tick -= new EventHandler(ev);

создает новый объект EventHandler. Он никогда не удалит существующий EventHandler. Чтобы получить желаемую функциональность, вы должны передать EventHandlers, а не MyDelegates, методам добавления и удаления:

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

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

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

Вызывающий код должен будет отслеживать добавленные EventHandlers, чтобы он мог передать тот же объект EventHandler, когда пришло время отказаться от подписки.

3 голосов
/ 17 февраля 2009

Исходный код работает нормально, если MyDelegate 'ev', переданный в addEvent и removeEvent, является одним и тем же экземпляром объекта (например, если есть поле MyDelegate уровня класса) который содержит экземпляр или если вы следуете советам нескольких других здесь и сохраняете объект (ы) MyDelegate в словаре).

Я подозреваю, что проблема в том, что код, вызывающий addEvent и removeEvent, передает новые MyDelegate экземпляры, указывающие на некоторый метод-обработчик, например:

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

В этом случае addEvent и removeEvent создают EventHandler делегатов, которые указывают на разные адреса методов, даже если эти делегаты в свою очередь указывают на один и тот же метод (this.HandlerMethod). Это связано с тем, что EventHandler делегирует, что add и remove создают точку для метода MyDelegate.Invoke() в разных экземплярах MyDelegate, а не прямо на адрес this.HandlerMethod.

2 голосов
/ 16 февраля 2009

Ваша проблема связана с наличием вспомогательных методов для этого. Без них работает как положено, с ними не знает что отцепить.

Чтобы исправить это, вам потребуется вести словарь со значением, являющимся EventHandler, созданным в методе перехвата, чтобы вы могли удалить это значение позже.

Что-то вроде:

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];
}

Вы должны добавить соответствующие проверки, если элемент существует.

Вы также можете изменить тип параметра, и он будет работать как положено.

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

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

addEvent(new EventHandler(...));
removeEvent(new EventHandler(...));
1 голос
/ 16 февраля 2009

Вы можете просто отменить подписку, сославшись на название вашего метода обработки, например:

public void removeEvent(MyDelegate ev)
{
    myTimer.Tick -= ev as EventHandler;
}
0 голосов
/ 03 марта 2016

Это должно работать:

private void timer_Tick(object sender, EventArgs e)
{
    try
    {
        // Disallow re-entry
        timer.Tick -= timer_Tick;
        . . .
    }
    finally
    {
        timer.Tick += timer_Tick;
    }
}
0 голосов
/ 16 февраля 2009

Я не знаю, что вы делаете неправильно, но обычный подход, который я бы использовал для таймеров, состоял бы в том, чтобы подписаться на событие Tick, а затем отключить таймер, если вы не хотите получать события , снова включив, когда вы делаете.

Может не помочь вам, если к событию подключено более одного обработчика событий, но, надеюсь, что-нибудь пригодится.

0 голосов
/ 16 февраля 2009

При добавлении и удалении обработчиков событий вы каждый раз создаете новую оболочку для своего делегата. Итак, в вашем методе удаления он пытается удалить новый объект EventHandler, который никогда не был добавлен в качестве прослушивателя события.

Если вы хотите продолжать использовать этот тип установки, вы можете вставить свои EventHandlers в словарь. В методе addEvent вставьте только что созданный EventHandler в свой словарь, а в методе removeEvent извлеките EventHandler из словаря и удалите его вместо создания нового.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...