2010-04-23 31 views
43

Trong ứng dụng .NET của tôi, tôi đang đăng ký các sự kiện từ một lớp khác. Đăng ký có điều kiện. Tôi đang đăng ký các sự kiện khi điều khiển hiển thị và hủy đăng ký khi nó trở nên vô hình. Tuy nhiên, trong một số điều kiện tôi không muốn hủy đăng ký sự kiện ngay cả khi điều khiển không hiển thị vì tôi muốn kết quả của một thao tác đang diễn ra trên một chuỗi nền.Cách xác định xem một sự kiện đã được đăng ký

Có cách nào để tôi có thể xác định xem một lớp học đã đăng ký sự kiện đó chưa?

Tôi biết chúng tôi có thể làm điều đó trong lớp học sẽ nâng cao sự kiện đó bằng cách kiểm tra sự kiện cho null, nhưng tôi làm cách nào để làm điều đó trong lớp học sẽ đăng ký sự kiện đó?

+2

Kiểm tra liên kết này http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/d7d8791f-6aef-4fda-ae0e-5eddcb856706/ –

+0

nếu nó chỉ về thời tiết * ai * được đăng ký: ´bool subscribedTo = theEvent! = null´ – Mark

Trả lời

51

Từ khóa event được phát minh rõ ràng để ngăn bạn làm những gì bạn muốn làm. Nó hạn chế quyền truy cập vào đối tượng cơ bản delegate để không ai có thể trực tiếp gây rối với các đăng ký xử lý sự kiện mà nó lưu trữ. Sự kiện là người truy cập cho một đại biểu, giống như một thuộc tính là người truy cập cho một trường. Thuộc tính chỉ cho phép nhận và đặt, sự kiện chỉ cho phép thêm và xóa.

Điều này giúp mã của bạn an toàn, mã khác chỉ có thể xóa trình xử lý sự kiện nếu nó biết phương thức xử lý sự kiện và đối tượng đích. Ngôn ngữ C# đặt một lớp bảo mật bổ sung tại chỗ bằng cách không cho phép bạn đặt tên cho đối tượng đích.

Và WinForms đặt một lớp bảo mật bổ sung tại chỗ để nó trở nên khó khăn ngay cả khi bạn sử dụng Phản chiếu.Nó lưu trữ delegate trường hợp trong một EventHandlerList với bí mật "cookie" làm khóa, bạn phải biết cookie để khai thác đối tượng ra khỏi danh sách.

Vâng, đừng đến đó. Đó là tầm thường để giải quyết vấn đề của bạn với một chút mã trên cuối cùng của bạn:

private bool mSubscribed; 

private void Subscribe(bool enabled) 
{ 
    if (!enabled) textBox1.VisibleChanged -= textBox1_VisibleChanged; 
    else if (!mSubscribed) textBox1.VisibleChanged += textBox1_VisibleChanged; 

    mSubscribed = enabled; 
} 
+4

Bạn có thể có bất kỳ blog, video 9 kênh hoặc bài viết nào về MSDN nói về phương pháp thiết kế đằng sau việc tạo sự kiện * rất khó tương tác không? Có lẽ nếu tôi hiểu * lý do tại sao *, và những gì * dự định * cơ chế để thực hiện một số điều bình thường (thường), tôi có thể có một thời gian dễ dàng hơn đến với các giải pháp tầm thường cho bộ vấn đề của riêng tôi. –

+1

Sự kiện của bạn không khó tương tác. Lộn xộn với sự kiện * của ai đó khác được thực hiện khó khăn, đó là rối tung với các bộ phận riêng tư. Đặt câu hỏi về nó. –

+2

Được rồi, * tại sao * lại gây rối với các sự kiện của người khác một cách khó khăn? –

0

Bạn không thể nhớ mình đã đăng ký chưa? Cách tiếp cận đó làm việc tốt cho tôi cho đến nay. Ngay cả khi bạn có rất nhiều sự kiện hoặc đối tượng, bạn vẫn có thể muốn nhớ rằng (trong từ điển, chẳng hạn).

Mặt khác, thay đổi mức hiển thị là, ít nhất đối với tôi, không phải là điểm tốt để đăng ký/hủy đăng ký. Tôi thường đi với xây dựng/Xử lý, đó là rõ ràng hơn mỗi lần thay đổi tầm nhìn.

6

Giả sử bạn không có quyền truy cập vào nội bộ của lớp tuyên bố sự kiện, bạn không có cách nào để thực hiện trực tiếp. Sự kiện chỉ hiển thị các toán tử +=-=, không có gì khác. Bạn sẽ cần một lá cờ hoặc một số cơ chế khác trong lớp đăng ký của bạn để biết bạn đã đăng ký hay chưa.

1

Bạn có thể đặt logic ra quyết định vào phương thức kích hoạt sự kiện không? Giả sử bạn đang sử dụng Winforms nó sẽ giống như thế này:

if (MyEvent != null && isCriteriaFulfilled) 
{ 
    MyEvent(); 
} 

đâu isCriteriaFulfilled được xác định bởi có thể nhìn thấy logic của bạn/vô hình.

// CẬP NHẬT /////

Tiếp tục để comment 1 của bạn sẽ không làm cho tinh thần để thay đổi hành vi bên trong xử lý sự kiện của bạn tùy thuộc vào giá trị của this.Visible?

a.Delegate += new Delegate(method1); 
... 
private void method1() 
{ 
    if (this.Visible) 
     // Do Stuff 
} 

Hoặc nếu bạn thực sự phải đi với đăng ký và hủy đăng ký:

private Delegate _method1 = null; 
... 
if(this.visible) 
{ 
    if (_method1 == null) 
     _method1 = new Delegate(method1); 
    a.Delegate += _method1; 
} 
else if (_method1 != null) 
{ 
    a.Delegate -= _method1; 
} 
+1

Tôi tự hỏi liệu 'isCriteriaFulfilled' có tốt hơn về mặt ngữ pháp không? –

+0

Tôi đang làm như sau nếu (this.visible) { a.Delegate + = new Delegate (method1); } else { a.Delegate - = new Delegate (method1); } – Ram

+0

@Ram: Đã cập nhật câu trả lời. –

1

Đơn giản chỉ cần kiểm tra xem điều khiển là có thể nhìn thấy hay không bất cứ khi nào xử lý sự kiện được kích hoạt.

+0

Tôi không muốn làm điều đó vì các sự kiện được kích hoạt ở khoảng thời gian thường xuyên và tôi muốn sử dụng chúng chỉ khi điều khiển của tôi là vô hình. nếu tôi làm những gì bạn đang nói, nó sẽ là một hit hiệu suất. – Ram

+0

@Ram: Tại sao bạn nghĩ rằng đó sẽ là một hit hiệu suất? Bạn đã đo lường sự thay đổi về hiệu suất chưa? –

+0

@Phil: Xin chào Phil, Đây là một hit hiệu quả khi tôi làm điều này với nhiều hình thức và nhiều sự kiện. Mỗi hình thức xử lý dữ liệu theo cách khác nhau. Vì vậy, để tránh xử lý dữ liệu, tôi chỉ đăng ký các sự kiện là biểu mẫu hiển thị. Tôi tin rằng việc sử dụng boolean sẽ là một lựa chọn tốt. – Ram

2
/// <summary> 
    /// Determine if a control has the event visible subscribed to 
    /// </summary> 
    /// <param name="controlObject">The control to look for the VisibleChanged event</param> 
    /// <returns>True if the control is subscribed to a VisibleChanged event, False otherwise</returns> 
    private bool IsSubscribed(Control controlObject) 
    { 
    FieldInfo event_visible_field_info = typeof(Control).GetField("EventVisible", 
     BindingFlags.Static | BindingFlags.NonPublic); 
    object object_value = event_visible_field_info.GetValue(controlObject); 
    PropertyInfo events_property_info = controlObject.GetType().GetProperty("Events", 
     BindingFlags.NonPublic | BindingFlags.Instance); 
    EventHandlerList event_list = (EventHandlerList)events_property_info.GetValue(controlObject, null); 
    return (event_list[object_value] != null); 
    } 
0

Tôi chỉ mở rộng về câu trả lời Hans'. Tôi chỉ cố gắng đảm bảo rằng tôi không cài đặt trình xử lý của mình nhiều lần và không xóa nó khi tôi vẫn cần. Điều này không bảo vệ khỏi người gọi độc hại hoặc gây khó chịu hủy đăng ký nhiều lần, vì bạn cần phải theo dõi người gọi và điều đó sẽ mở ra cho bạn việc đăng ký lặp lại vượt quá cơ chế theo dõi.

// Tracks how many times the ReflectionOnlyResolveHandler has been requested. 
private static int _subscribers = 0; 

/// <summary> 
/// Register or unregister the ReflectionOnlyResolveHandler. 
/// </summary> 
/// <param name="enable"></param> 
public static void SubscribeReflectionOnlyResolve(bool enable) 
{ 
    lock(_lock) 
    { 
     if (_subscribers > 0 && !enable) _subscribers -= 1; 
     else if (enable) _subscribers += 1; 

     if (enable && _subscribers == 1) 
      AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ReflectionHelper.ReflectionOnlyResolveHandler; 
     else if (_subscribers == 0) 
      AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= ReflectionHelper.ReflectionOnlyResolveHandler; 
    } 
} 
+0

Người gọi ở trên không thực sự là "người đăng ký", họ chỉ yêu cầu lớp trợ giúp đăng ký trình xử lý của họ. –

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