2009-02-16 20 views
8

Tôi cố gắng để thêm và loại bỏ các sự kiện từ một bộ đếm thời gian và tôi có đoạn mã sau:C# thêm và loại bỏ các sự kiện từ một timer

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

Tôi không biết Nếu Im làm bất cứ điều gì ngu ngốc khi cố gắng thêm và loại bỏ các đại biểu trong thời trang này, tôi có thể thêm các đại biểu và khiến họ được kích hoạt như mong đợi. Tuy nhiên, khi tôi cố gắng loại bỏ các sự kiện, họ tiếp tục kích hoạt Timers Tick.

Có ai có thể thấy bất kỳ điều gì rõ ràng là sai không?

+0

bạn có thể hiển thị các definiton của MyDelegate và giải thích lý do tại sao nó là có? –

Trả lời

8

Tôi tin rằng mã này:

myTimer.Tick -= new EventHandler(ev); 

tạo ra một đối tượng EventHandler mới. Nó sẽ không bao giờ loại bỏ EventHandler hiện tại. Để có được các chức năng mà bạn muốn, bạn nên đi qua trong EventHandlers, không MyDelegates, vào add và remove các phương pháp:

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

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

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

Mã gọi sẽ phải tiếp tục theo dõi những EventHandlers thêm, để nó có thể vượt qua trong cùng một đối tượng EventHandler khi đã đến lúc hủy đăng ký.

+1

Mã hoạt động như - không cần mã gọi để giữ danh sách Eventhandlers. Nhà lưu trữ của sự kiện sẽ tìm kiếm đại biểu thực tế và xóa ivocationItem proprt. Bạn có thể gọi removeEvent (MyTickHandler); –

+0

Tôi biết rằng tôi đã có một khoảnh khắc lập trình viên ở đó! Bạn đúng khi nói rằng sử dụng EventHandlers thay vì Delegates hoạt động. Cảm ơn bạn đã giúp đỡ! –

1

Bạn chỉ có thể bỏ đăng ký bằng cách tham khảo tên của phương pháp thậm chí xử lý của bạn như vậy:

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

Thật không may, điều này tạo ra lỗi trình biên dịch "Không thể chuyển đổi hoàn toàn loại 'myDelegate' thành 'System.EventHandler'" –

+0

Điều đó sẽ không tạo ra sự khác biệt nào. Nếu bạn bỏ qua EventHandler mới (...) hoặc các hàm tạo tương tự, chúng sẽ được thêm vào khi bạn biên dịch. – Samuel

+0

Bạn có thể bỏ mặc dù không? –

0

Khi thêm và loại bỏ các xử lý sự kiện bạn đang tạo một wrapper mới cho mỗi lần đại biểu của mình. Vì vậy, trong phương pháp xóa của bạn, nó đang cố gắng xóa đối tượng EventHandler mới EventHandler chưa bao giờ được thêm làm người nghe cho sự kiện này ngay từ đầu.

Nếu bạn muốn tiếp tục sử dụng loại thiết lập này, bạn có thể gắn EventHandlers của mình vào từ điển. Trong phương thức addEvent, hãy gắn EventHandler mới được tạo vào từ điển của bạn và trong phương thức removeEvent, kéo EventHandler từ từ điển và loại bỏ nó thay vì khởi tạo một từ mới.

2

Sự cố của bạn xuất phát từ việc có phương pháp trợ giúp để thực hiện việc này. Không có chúng, nó hoạt động như mong đợi, với chúng nó không biết phải tháo ra gì.

Để khắc phục điều này, bạn sẽ cần duy trì một từ điển có giá trị là EventHandler được tạo bằng phương pháp hooking để bạn có thể xóa giá trị đó sau này.

Cái gì như:

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

Bạn nên thêm kiểm tra thích hợp nếu phần tử tồn tại.

Bạn cũng có thể thay đổi loại thông số và nó sẽ hoạt động như mong đợi.

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

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

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

Tôi không biết mình đang làm gì sai, nhưng cách tiếp cận thông thường tôi sẽ sử dụng cho Timers sẽ được đăng ký vào các sự kiện Tick, và sau đó vô hiệu hóa Timer khi bạn không muốn nhận các sự kiện, bật lại khi bạn làm.

Không thể giúp bạn nếu bạn có nhiều trình xử lý sự kiện được kết nối với sự kiện, nhưng hy vọng một số trường hợp sử dụng.

3

Mã ban đầu hoạt động tốt, miễn là MyDelegate 'ev' truyền vào addEventremoveEvent là trường hợp đối tượng tương tự (Ví dụ, nếu có một lớp cấp MyDelegate trường chứa dụ hoặc nếu bạn làm theo các lời khuyên của nhiều người khác ở đây và giữ các đối tượng MyDelegate trong một Từ điển).

tôi nghi ngờ vấn đề là mã gọi addEventremoveEvent là đi qua MyDelegate trường mới trỏ đến một số phương pháp xử lý, như vậy:

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

Trong trường hợp này addEventremoveEvent đang tạo EventHandler đại biểu mà điểm đến các địa chỉ phương thức khác nhau mặc dù các đại biểu đó lần lượt trỏ đến cùng một phương thức (this.HandlerMethod). Điều này là do các đại biểu EventHandler rằng addremove tạo điểm đến phương thức MyDelegate.Invoke() trên các trường hợp MyDelegate khác nhau thay vì trực tiếp đến địa chỉ this.HandlerMethod.

+1

Thêm vào sự nghi ngờ của jester, điều này cũng có thể xảy ra nếu người gọi chỉ cần chuyển tên của một phương thức khớp với chữ ký của đại biểu, ví dụ: addEvent (this.MyCallback) ;. Trong trường hợp này, đại biểu được tạo ra ngầm, dẫn đến vấn đề được mô tả. –

0

này nên làm việc:

private void timer_Tick(object sender, EventArgs e) 
{ 
    try 
    { 
     // Disallow re-entry 
     timer.Tick -= timer_Tick; 
     . . . 
    } 
    finally 
    { 
     timer.Tick += timer_Tick; 
    } 
} 
Các vấn đề liên quan