2009-02-16 18 views
8

我試圖添加和刪除一個計時器事件刪除事件,我有以下代碼:C#中添加和定時器

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

我不知道如果Im做任何愚蠢的事在嘗試添加並以這種方式刪除代表,我可以添加代表並讓他們按預期發射。但是,當我嘗試刪除事件時,它們會繼續在Timers Tick上觸發。

任何人都可以看到任何明顯錯誤?

+0

你能顯示MyDelegate的definiton,並解釋爲什麼它的存在? – 2009-02-16 20:28:04

回答

8

我相信這個代碼:

myTimer.Tick -= new EventHandler(ev); 

創建一個新的事件處理程序的對象。它永遠不會刪除現有的EventHandler。爲了得到你想要的,你應該傳遞事件處理,而不是MyDelegates的功能,來添加和移除方法:

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

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

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

調用代碼將不得不繼續增加跟蹤事件處理的,因此,它可以傳遞相同的EventHandler對象,當它是時候取消訂閱。

1

你應該只能夠通過像這樣引用你甚至處理方法的名稱退訂:

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

不幸的是這會產生一個編譯器錯誤「不能隱式地將類型'myDelegate'轉換爲'System.EventHandler'」 – 2009-02-16 17:53:45

+0

這沒有什麼區別。如果您省略了新的EventHandler(...)或類似的構造函數,那麼在編譯時會添加它們。 – Samuel 2009-02-16 17:53:49

+0

你可以施放它嗎? – 2009-02-16 20:06:56

0

當添加和刪除事件處理程序要創建每次您的委託一個新的包裝。因此,在您的刪除方法中,它試圖刪除從未添加爲首位偵聽器的EventHandler對象。

如果你想繼續使用這種類型的設置,你可以將你的EventHandler粘貼到Dictionary中。在addEvent方法中,將新創建的EventHandler粘貼到字典中,然後在removeEvent方法中,從字典中提取EventHandler並刪除它,而不是實例化一個新的。

2

你的問題來自助手方法來做到這一點。沒有它們,它會按預期工作,與他們不知道要解除什麼。

要解決這個問題,您需要維護一個字典,其值是在掛鉤方法中創建的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(...)); 
0

我不知道你做錯了什麼,但通常的做法我會用定時器將訂閱Tick事件,然後禁用定時器,當你不希望接收事件,當你做時重新啓用。

如果您有多個事件處理程序連接到事件,但希望有一些用處,可能無法幫助您。

3

最初的代碼工作正常,只要MyDelegateev」傳遞到addEventremoveEvent是同一個對象實例(例如,如果沒有包含實例類級別MyDelegate場或者如果你按照在這裏的其他幾個人的建議,並保持MyDelegate對象在一個詞典)。

我懷疑問題是代碼調用addEventremoveEvent正在通過新的MyDelegate實例指向一些處理方法,像這樣:

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

在這種情況下,addEventremoveEvent創建EventHandler代表該點不同的方法地址,即使這些代表反過來也指向相同的方法(this.HandlerMethod)。這是因爲EventHandler代表addremove創建指向不同MyDelegate實例上的MyDelegate.Invoke()方法,而不是直接指向地址this.HandlerMethod

0

這應該工作:

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