2009-07-19 29 views
5

Sự cố: Tôi có một lớp tài liệu chứa danh sách các đối tượng. Các đối tượng này tăng các sự kiện như SolutionExpired, DisplayExpired v.v. Tài liệu cần phản hồi điều này.Xóa tất cả trình xử lý sự kiện trong một lần

Tài liệu đôi khi có thể trao đổi các đối tượng, nhưng một đối tượng không bao giờ nên là 'một phần' của nhiều tài liệu.

Lớp tài liệu của tôi chứa một loạt các phương thức đóng vai trò là trình xử lý sự kiện. Bất cứ khi nào một đối tượng nhập tài liệu, tôi sử dụng AddHandler để thiết lập các sự kiện và bất cứ khi nào một đối tượng bị xóa khỏi tài liệu tôi sử dụng RemoveHandler để hoàn tác thiệt hại. Tuy nhiên, có những trường hợp rất khó để đảm bảo tất cả các bước được thực hiện đúng và do đó tôi có thể kết thúc với trình xử lý sự kiện giả mạo.

Câu chuyện dài ngắn; làm thế nào để loại bỏ tất cả các trình xử lý đang trỏ đến một phương pháp cụ thể? Lưu ý, tôi không có danh sách các nguồn sự kiện tiềm năng, chúng có thể được lưu trữ ở mọi nơi.

Cái gì như:

RemoveHandler *.SolutionExpired, AddressOf DefObj_SolutionExpired 
+0

bản sao có thể có của [Cách xóa tất cả trình xử lý sự kiện khỏi điều khiển] (http://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-a-control) – ChrisF

+0

Có thể bản sao của [Làm thế nào để loại bỏ tất cả xử lý sự kiện từ một điều khiển] (https://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-a-control) –

Trả lời

5

Bạn có thể sử dụng Delegate.RemoveAll(). (Phần bạn quan tâm là trong button2_Click)

public void Form_Load(object sender, EventArgs e) 
{ 
    button1.Click += new EventHandler(button1_Click); 
    button1.Click += new EventHandler(button1_Click); 
    button2.Click += new EventHandler(button2_Click); 
    TestEvent += new EventHandler(Form_TestEvent); 
} 
event EventHandler TestEvent; 
void OnTestEvent(EventArgs e) 
{ 
    if (TestEvent != null) 
     TestEvent(this, e); 
} 
void Form_TestEvent(object sender, EventArgs e) 
{ 
    MessageBox.Show("TestEvent fired"); 
} 
void button2_Click(object sender, EventArgs e) 
{ 
    Delegate d = TestEvent as Delegate; 
    TestEvent = Delegate.RemoveAll(d, d) as EventHandler; 
} 
void button1_Click(object sender, EventArgs e) 
{ 
    OnTestEvent(EventArgs.Empty); 
} 

Bạn nên lưu ý rằng nó không làm thay đổi nội dung của các đại biểu bạn vượt qua vào nó, nó sẽ trả về một đại biểu thay đổi. Do đó, bạn sẽ không thể thay đổi các sự kiện trên nút bạn đã bỏ trên biểu mẫu từ biểu mẫu, vì button1.Click chỉ có thể sử dụng += hoặc -= được sử dụng trên biểu mẫu chứ không phải =. Điều này sẽ không biên dịch:

button1.Click = Delegate.RemoveAll(d, d) as EventHandler; 

Ngoài ra, hãy chắc chắn rằng bất cứ nơi nào bạn đang thực hiện điều này, bạn đang xem ra cho tiềm năng của điều kiện chủng tộc.Bạn có thể kết thúc với một số hành vi thực sự kỳ lạ nếu bạn đang loại bỏ trình xử lý từ một sự kiện đang được gọi bởi một chủ đề khác!

+4

Tôi không hiểu điều này có thể chấp nhận được, với điều kiện OP cần phải loại bỏ các trình xử lý từ một sự kiện mà anh ta không có quyền truy cập ở cấp độ riêng tư. Chắc chắn là tôi đang thiếu gì đó! –

+1

Đây cũng là C# trong khi câu hỏi của OP là về vb.net. Trong khi cả hai có rất nhiều chồng chéo, cú pháp sự kiện là một trong những nơi chúng rất khác nhau – user81993

1
public class TheAnswer 
{ 
    public event EventHandler MyEvent = delegate { }; 

    public void RemoveFromMyEvent(string methodName) 
    { 
     foreach (var handler in MyEvent.GetInvocationList()) 
     { 
      if (handler.Method.Name == methodName) 
      { 
       MyEvent -= (EventHandler)handler; 
      } 
     } 
    } 
} 

EDIT 2: Xin lỗi vì sự hiểu lầm của tôi - Tôi thấy rằng bạn đã khá rõ ràng về việc không có quyền truy cập vào các nguồn sự kiện trong bài viết gốc của bạn.

Cách đơn giản nhất tôi có thể nghĩ đến để giải quyết vấn đề này liên quan đến việc triển khai Từ điển được chia sẻ của các liên kết đối tượng đến tài liệu. Khi một đối tượng nhập một tài liệu, hãy kiểm tra từ điển cho một ràng buộc hiện có với một tài liệu khác; nếu có, hãy loại bỏ các trình xử lý đề cập đến tài liệu cũ trước khi thêm chúng cho tài liệu mới. Dù bằng cách nào, cập nhật từ điển với ràng buộc mới. Tôi nghĩ rằng trong hầu hết các trường hợp, tác động của bộ nhớ và hiệu suất sẽ không đáng kể: trừ khi bạn đang xử lý hàng chục nghìn đối tượng nhỏ và thường xuyên trao đổi giữa các tài liệu, chi phí bộ nhớ của mỗi cặp khóa/giá trị và hiệu suất đạt được cho mỗi hoạt động tra cứu nên khá nhỏ.

Cách khác: nếu bạn có thể phát hiện (trong trình xử lý sự kiện tài liệu) người gửi sự kiện không còn liên quan đến tài liệu, bạn có thể tách các sự kiện ở đó.

Đây có vẻ như là loại ý tưởng bạn có thể đã từ chối - nhưng có thể không!

+0

Ben, cảm ơn vì đã đăng điều này. Tôi e rằng nó không có ý nghĩa với tôi (hoặc trình biên dịch VB cho vấn đề đó). Bạn có thể vui lòng đăng C# gốc không? –

+1

Tôi biết tôi nên để nguyên phiên bản C# gốc. :-) –

+0

Cảm ơn Ben, tôi thấy những gì bạn đang làm ở đây, nhưng nếu tôi không nhầm chức năng này giả định tôi có một tham chiếu đến trường hợp đó là nâng cao các sự kiện. Những vật thể này có thể từ lâu đã biến mất trên đường chân trời vào một danh sách khác ở đâu đó. Tôi bắt đầu nghĩ rằng có thể không thực hiện được điều này vì các đại biểu xử lý được định nghĩa trong lớp làm tăng sự kiện, chứ không phải lớp xác định trình xử lý. –

1

Sử dụng Delegate.RemoveAll (có thể sử dụng phản chiếu nếu phiên bản Đại biểu là riêng tư).

+0

Bởi vì tôi cần phải có một thể hiện của nguồn cho việc này. Tôi nghĩ rằng ... Tôi không còn quyền truy cập vào đối tượng tăng sự kiện, chỉ có trình xử lý. –

Các vấn đề liên quan