2011-07-26 36 views
12

Tôi có nút điều khiển và tôi cần phải xóa tất cả trình xử lý sự kiện được đính kèm theo số Click event.Làm cách nào để xóa tất cả trình xử lý sự kiện của sự kiện 'Nhấp' của 'Nút'?

Làm cách nào có thể?

Button button = GetButton(); 
button.Click.RemoveAllEventHandlers(); 
+0

Bạn có thể thay thế Nút bằng MyButtonClass không? –

+0

Tôi nghĩ rằng cách dễ dàng hơn là vô hiệu hóa nút – V4Vendetta

+0

Tôi muốn thêm chỉ một trình xử lý sự kiện sau đó để vô hiệu hóa sẽ không giúp ích gì. –

Trả lời

10

Bạn không thể, về cơ bản - ít nhất là không phải không có sự phản ánh và rất nhiều grubbiness.

Sự kiện nghiêm chỉnh "đăng ký, hủy đăng ký" - bạn không thể hủy đăng ký trình xử lý của người khác, bất kỳ điều gì khác ngoài việc bạn có thể thay đổi tham chiếu của người khác thành đối tượng.

+0

đó là chính xác những gì tôi muốn; hủy đăng ký người xử lý của người khác! Tôi đang sử dụng nút tùy chỉnh từ bên thứ ba và muốn xóa trình xử lý sự kiện nhấp của tác giả ... –

+0

@William: Bạn không thể không dựa vào chi tiết triển khai và phản chiếu, trừ khi nút tùy chỉnh cho thấy hành vi như vậy . Việc đóng gói các sự kiện là các trình xử lý không can thiệp lẫn nhau. –

+0

có gì sai khi sử dụng sự phản chiếu cho nó? –

4

Tôi tìm thấy câu trả lời này đây trên StackOverflow:

How to remove all event handlers from a control

private void RemoveClickEvent(Button b) 
{ 
    FieldInfo f1 = typeof(Control).GetField("EventClick", 
     BindingFlags.Static | BindingFlags.NonPublic); 
    object obj = f1.GetValue(b); 
    PropertyInfo pi = b.GetType().GetProperty("Events", 
     BindingFlags.NonPublic | BindingFlags.Instance); 
    EventHandlerList list = (EventHandlerList)pi.GetValue(b, null); 
    list.RemoveHandler(obj, list[obj]); 
} 

Những poster origional tìm thấy here:

+2

Đó là thực hiện cụ thể mặc dù - câu trả lời xuất hiện trong năm 2008, tôi thậm chí sẽ không muốn nói cho dù nó sẽ làm việc trên .NET 4. Đó là một ý tưởng thực sự xấu dựa vào những thứ như thế này. –

+2

cảm ơn nhưng dòng này luôn trả về null: typeof (Control) .GetField ("EventClick", BindingFlags.Static | BindingFlags.NonPublic); –

+0

Tôi đã triển khai một giải pháp tương tự hoạt động bằng cách sử dụng một vài phương thức nội bộ của đối tượng EventHandlerList. Xem câu trả lời http://stackoverflow.com/questions/11031149/solution-to-remove-event-handler-dynamically-using-reflection-is-there-a-bett –

28

Note: Kể từ khi câu hỏi mà tôi gửi ban đầu của tôi câu trả lời đã được đóng as a duplicate của câu hỏi này, tôi đăng chéo một phiên bản cải tiến của câu trả lời của tôi lại. Câu trả lời này chỉ áp dụng cho WPF. Nó sẽ không hoạt động trên Windows Forms hoặc bất kỳ khung giao diện người dùng nào khác.

Dưới đây là một phương pháp tiện ích hữu ích để xóa tất cả trình xử lý sự kiện đã đăng ký với sự kiện được định tuyến trên phần tử đã cho. Bạn có thể trivially chuyển đổi này sang một phương pháp mở rộng nếu bạn muốn.

/// <summary> 
/// Removes all event handlers subscribed to the specified routed event from the specified element. 
/// </summary> 
/// <param name="element">The UI element on which the routed event is defined.</param> 
/// <param name="routedEvent">The routed event for which to remove the event handlers.</param> 
public static void RemoveRoutedEventHandlers(UIElement element, RoutedEvent routedEvent) 
{ 
    // Get the EventHandlersStore instance which holds event handlers for the specified element. 
    // The EventHandlersStore class is declared as internal. 
    var eventHandlersStoreProperty = typeof(UIElement).GetProperty(
     "EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic); 
    object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null); 

    // If no event handlers are subscribed, eventHandlersStore will be null. 
    // Credit: https://stackoverflow.com/a/16392387/1149773 
    if (eventHandlersStore == null) 
     return; 

    // Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance 
    // for getting an array of the subscribed event handlers. 
    var getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod(
     "GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 
    var routedEventHandlers = (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(
     eventHandlersStore, new object[] { routedEvent }); 

    // Iteratively remove all routed event handlers from the element. 
    foreach (var routedEventHandler in routedEventHandlers) 
     element.RemoveHandler(routedEvent, routedEventHandler.Handler); 
} 

Bạn có thể sau đó dễ dàng gọi phương thức tiện ích này cho sự kiện Click của nút bấm của bạn:

RemoveRoutedEventHandlers(button, Button.ClickEvent); 

Sửa: Tôi đã sao chép bug fix implemented by corona, mà dừng lại phương pháp này từ ném một NullReferenceException khi không có sự kiện xử lý được đăng ký. Tín dụng (và upvotes) nên đi đến câu trả lời của họ.

+0

Có thể thực hiện điều này trong Silverlight không? Silverlight không có RoutedEventHandlerInfo. –

+0

... Điều này có thể được mở rộng thành một phương pháp mở rộng không? Điều đó sẽ khá ngọt ngào ... – Will

1

Tôi gặp vấn đề về lỗi null với mã Jamie Dixon được đăng để tính đến tài khoản không có sự kiện Nhấp chuột.

private void RemoveClickEvent(Control control) 
{ 
    // chenged "FieldInfo f1 = typeof(Control)" to "var f1 = b.GetType()". By changing to 
    // the type of the passed in control we can use this for any control with a click event. 
    // using var allows for null checking and lowering the chance of exceptions. 

    var fi = control.GetType().GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic); 
    if (fi != null) 
    { 
     object obj = fi.GetValue(control); 
     PropertyInfo pi = control.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance); 
     EventHandlerList list = (EventHandlerList)pi.GetValue(control, null); 
     list.RemoveHandler(obj, list[obj]); 
    } 

} 

Sau đó, một thay đổi nhỏ và nó sẽ là cho bất kỳ sự kiện nào.

private void RemoveClickEvent(Control control, string theEvent) 
{ 
    // chenged "FieldInfo f1 = typeof(Control)" to "var f1 = b.GetType()". By changing to 
    // the type of the passed in control we can use this for any control with a click event. 
    // using var allows for null checking and lowering the chance of exceptions. 

    var fi = control.GetType().GetField(theEvent, BindingFlags.Static | BindingFlags.NonPublic); 
    if (fi != null) 
    { 
     object obj = fi.GetValue(control); 
     PropertyInfo pi = control.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance); 
     EventHandlerList list = (EventHandlerList)pi.GetValue(control, null); 
     list.RemoveHandler(obj, list[obj]); 
    } 

} 

Tôi tưởng tượng điều này có thể được thực hiện tốt hơn nhưng nó hoạt động cho nhu cầu hiện tại của tôi. Hy vọng điều này rất hữu ích cho ai đó.

10

Chỉ muốn mở rộng thói quen của Douglas một chút, điều tôi thích rất nhiều. Tôi thấy tôi cần thêm kiểm tra null bổ sung vào eventHandlersStore để xử lý bất kỳ trường hợp nào mà phần tử được chuyển không có bất kỳ sự kiện nào được đính kèm.

/// <summary> 
/// Removes all event handlers subscribed to the specified routed event from the specified element. 
/// </summary> 
/// <param name="element">The UI element on which the routed event is defined.</param> 
/// <param name="routedEvent">The routed event for which to remove the event handlers.</param> 
public static void RemoveRoutedEventHandlers(UIElement element, RoutedEvent routedEvent) 
{ 
    // Get the EventHandlersStore instance which holds event handlers for the specified element. 
    // The EventHandlersStore class is declared as internal. 
    var eventHandlersStoreProperty = typeof(UIElement).GetProperty(
     "EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic); 
    object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null); 

    if (eventHandlersStore == null) return; 

    // Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance 
    // for getting an array of the subscribed event handlers. 
    var getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod(
     "GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 
    var routedEventHandlers = (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(
     eventHandlersStore, new object[] { routedEvent }); 

    // Iteratively remove all routed event handlers from the element. 
    foreach (var routedEventHandler in routedEventHandlers) 
     element.RemoveHandler(routedEvent, routedEventHandler.Handler); 
} 
Các vấn đề liên quan