2010-09-24 45 views
7

Khi tôi sử dụng AddHandler trong VB để thêm phương pháp riêng của tôi vào sự kiện Click:Thêm xử lý sự kiện riêng trước xử lý sự kiện khác

AddHandler Button.Click, AddressOf myButton_Click 

Tôi thấy rằng mã của tôi thực hiện cuối cùng - sau khi xử lý sự kiện khác cho Sự kiện Button_Click. Có cách nào để chèn trình xử lý sự kiện của tôi vào trước các sự kiện khác để nó thực thi trước không?

Tôi đã gắn thẻ câu hỏi này là C# cũng như VB, vui lòng sử dụng ngôn ngữ lập trình nếu bạn có bất kỳ đề xuất nào.
Cảm ơn!

Trả lời

5

Trình tự thực hiện các xử lý của một sự kiện duy nhất không thể được kiểm soát thông qua các hành vi cơ bản của một built-in sự kiện riêng của mình. MulticastDelegates là "túi" của các trình xử lý, và chúng chỉ lấy chúng một lần. Hãy nhớ rằng đây là cách hầu hết các nhà phát triển mong đợi điều này để làm việc, và nó có thể nguy hiểm để cho phép xử lý sự kiện phụ thuộc vào thứ tự. Trình xử lý sự kiện thường không biết về nhau, vì nếu chúng phụ thuộc vào việc được thực hiện trước hoặc sau một trình xử lý khác, trước tiên chúng phải biết sự tồn tại của trình xử lý khác (vi phạm thông tin vi phạm và một số nguyên tắc thiết kế khác), và thứ hai, nếu thứ tự đó thay đổi, hành vi sẽ bị hỏng.

Nếu bạn hiểu tất cả điều này và vẫn muốn kiểm soát thứ tự thực hiện xử lý sự kiện, thông tin sau sẽ giúp bạn đóng cửa.

  1. Tạo bộ sưu tập có trật tự các đại biểu của loại trình xử lý sự kiện được gọi là MyHandlers. Đây sẽ là một thay thế cho việc thực hiện MulticastDelegate của sự kiện thực tế.
  2. Tạo phương thức xử lý "chính" sẽ thực sự được đính kèm với sự kiện được tích hợp sẵn và sẽ lặp qua MyHandlers và gọi từng hàm.
  3. Xác định một số phương tiện để thêm và xóa trình xử lý khỏi danh sách. Một số điều này có thể được thực hiện với một sự kiện tùy chỉnh "thuộc tính", nhưng điều đó sẽ xác định chỉ thêm và loại bỏ các hành vi, không chèn.

Mã này có thể trông giống như sau:

private List<EventHandler> MyHandlers = new List<EventHandler>(); 

private void MasterClickHandler(object sender, EventArgs e) 
{ 
    foreach(var handler in MyHandlers) 
     handler(sender, e); 
} 

public event EventHandler MyControlButtonClick 
{ 
    add { MyHandlers.Add(value); } 
    remove { MyHandlers.Remove(value); } 
} 

public void InsertButtonClickHandler(EventHandler handler) 
{ 
    MyHandlers.Insert(handler,0); //calling this to add a handler puts the handler up front 
} 

... 

myForm.MyControl.Click += MasterClickHandler; 

Chú ý rằng bạn không còn gắn bộ xử lý khác hơn MasterClickHandler đến sự kiện thực tế; bạn không thể có bánh của bạn và ăn nó quá, cả trọng và giữ hành vi sự kiện cơ bản.Cũng không có hành vi "chèn" được tích hợp vào sự kiện "thuộc tính"; bạn phải định nghĩa một phương thức cho phép điều này. Cuối cùng, bạn không bao giờ nên tăng sự kiện MyControlButtonClick trực tiếp (mặc dù điều khiển của bạn là điều duy nhất có thể, điều này có thể được thực thi bằng cách kiểm tra mã). Bây giờ, khi bạn nhấp vào nút, sự kiện Click tích hợp sẵn của nút kích hoạt MasterEventHandler, sẽ thực thi các đại biểu trong MyHandlers theo cùng thứ tự mà chúng được gắn vào MyControlButtonClick (với bất kỳ thứ gì đã được chèn vào trước, ngược lại thứ tự chúng được chèn vào). Nếu bạn đặt mã này trong một điều khiển người dùng tùy chỉnh với Nút, bạn thậm chí có thể đặt tên sự kiện tùy chỉnh trên điều khiển của bạn Nhấp và điều khiển sẽ trông và hoạt động giống như Nút chứa, ngoại trừ việc nó có quyền kiểm soát bổ sung đối với chèn xử lý. Vẻ đẹp của toàn bộ điều này là không có gì về mã này buộc người tiêu dùng phải làm việc với nó như bất cứ điều gì khác hơn là một sự kiện vani bình thường.

11

Không dễ dàng.

Điều đó đang được nói, đừng làm điều đó. Mã của bạn không nên quan tâm đến thứ tự nó được gọi là gì - nó chỉ cần quan tâm đến nút được đề cập đã được nhấp vào. Tất cả các trình xử lý, kể cả các trình xử lý của bạn, sẽ thực thi. Nếu thứ tự quan trọng, bạn nên suy nghĩ lại về thiết kế của mình và sử dụng một số cơ chế khác để kiểm soát điều đó.

+0

+1 để được tư vấn tốt. –

4

Nó là một chi tiết thực hiện của VB.NET, nó có một cách thay thế để đối phó với các sự kiện bằng cách sử dụng các từ khóa WithEvents và Handles. Trình xử lý sự kiện sử dụng Handles được đăng ký bằng mã được tạo tự động trong hàm tạo biểu mẫu. Mã này sẽ chạy trước bất kỳ mã nào của bạn, bao gồm InitializeComponent hoặc câu lệnh AddHandler tùy chỉnh của bạn. Và do đó sẽ luôn luôn chạy đầu tiên.

Nhận mã của bạn để đảm bảo chạy đầu tiên là có thể. Rút ra lớp riêng của bạn từ Button và ghi đè lên các phương pháp OnClick:

Public Class MyButton 
    Inherits Button 

    Protected Overrides Sub OnClick(ByVal e As System.EventArgs) 
     '' Do your stuff here 
     ''.... 

     '' Other event handlers will run now: 
     MyBase.OnClick(e) 
    End Sub 
End Class 
2

Tôi gặp sự cố tương tự.

Tôi đã có một sự kiện: Đóng hai đối tượng khác nhau để nghe. Và tôi phải chắc chắn rằng sự kiện của đối tượng thứ nhất sẽ được gọi trước sự kiện thứ hai.

đây giải pháp của tôi của mình (trong C#):

public class Screen 
{ 
    public event EventHandler Closed; 
    public event EventHandler ScreenRemoved; 


    protected virtual void OnClosed() 
    { 
     if (Closed != null) 
     { 
      Closed.Invoke(this, EventArgs.Empty); 
     } 

     OnScreenRemoved(); 
    } 

    protected virtual void OnScreenRemoved() 
    { 
     if (ScreenRemoved != null) 
     { 
      ScreenRemoved.Invoke(this, EventArgs.Empty); 
     } 
    } 
} 

Bằng cách này cho tất cả các sự kiện mà tôi muốn được gọi đầu tiên:

m_Screen.Closed += Screen_Closed; 

Và đối với tất cả các sự kiện mà tôi muốn được gọi là last:

m_Screen.ScreenRemoved += new EventHandler(Screen_Closed); 

* cả hai cách thêm sự kiện đều giống nhau, có và không có "EventHandler mới()"

Hy vọng tôi sẽ hữu ích.

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