簡體   English   中英

攔截和取消WinForms按鈕的Click事件

[英]Intercepting and cancelling the Click event of a WinForms Button

有沒有一種方法可以從父控件中捕獲Button的Click事件,並防止在父控件中的變量為true時發生該事件?

例如:

private void AssignEventOverrides()
{
    foreach (Button button in Buttons) 
    {
        // Get the event assigned at design time
        var someUnknownEventHandler = GetTheClickHandlerSomehow(button);

        // Unsubscribe the unknown event
        button.Click -= SomeUnknownEventHandler;

        // Assign the intercepting event
        button.Click += button_Click;
    }
}

private void button_Click(object sender, EventArgs e)
{
    if (!preventClick)
    {
        // Fire the intercepted event that was previously unsubscribed
    }
}

希望有比上述示例更好的方法來執行此操作。 只是要注意,我對分配給上述按鈕的事件沒有任何控制權。 它們已在其他位置訂閱,並且如果使用方父控件上的變量為true,則只需阻止它們發生。

我的真實情況是:

我正在使用Windows Mobile 6.5(舊版應用程序重寫),我創建了一個面板控件,其中可以包含N個子控件。 面板控件允許iPhone樣式的垂直滾動。 我訂閱了子ControlMouseMove事件,並將變量_isScrolling設置為true MouseUp事件中,我將_isScrolling設置為false

由於ClickMouseUp之前發生,因此我可以在Click事件中進行檢查,以確保在按下按鈕時沒有發生滾動。 因此,基本上,如果發生面板滾動,則需要防止觸發Click事件(在設計時訂閱)。

這可能會提供一些有用的見解

如何從控件中刪除所有事件處理程序

具體來說,看看

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

作為解決問題的另一種方法,為什么不只是對托管表單進行子類化並尋找目標的點擊。 如果您的preventClick為true,則將消息標記為已處理,以防止其傳遞給孩子。

禁用按鈕而不是將父控件中的變量設置為true怎么辦?

更新:設置button.Enabled = false肯定會阻止Click事件引發:)

更新2(針對真實場景):考慮創建自定義按鈕

public class ScrollableButton : Button
{
    private bool _isScrolling;

    protected override void OnMouseMove(MouseEventArgs mevent)
    {
        _isScrolling = true;
        base.OnMouseMove(mevent);
    }

    protected override void OnMouseUp(MouseEventArgs mevent)
    {
        base.OnMouseUp(mevent);
        _isScrolling = false;
    }

    public bool IsScrolling { get; set; }

    protected override void OnClick(EventArgs e)
    {
        if (!_isScrolling)
            base.OnClick(e);
    }
}

只需將默認按鈕替換為可滾動按鈕即可。

感謝Hehewaffles的回答 ,這是我想出的解決方案:

/// <summary>
/// Dictionary for holding the controls design time Click EventHandlers.
/// </summary>
private Dictionary<Control, EventHandler> _interceptedClickEventHandlers;

/// <summary>
/// Recursively moves through the child controls assigning events for scrolling and replacing Click events 
/// with an interception EventHandler that prevents the Click event occuring if the Panel was scrolled.
/// </summary>
/// <param name="control">The control to handle the events for and whose children to recurse through.</param>
private void RecursivelySubscribeChildEvents(Control control)
{
    if (!(control is IPanelItem))
    {
        return;
    }

    // Subscribe the events for the scroll handling
    control.MouseDown += new MouseEventHandler(UIPanel_MouseDown);
    control.MouseMove += new MouseEventHandler(UIPanel_MouseMove);
    control.MouseUp += new MouseEventHandler(UIPanel_MouseUp);

    // Intercept the click event
    FieldInfo eventClickField = typeof(Control).GetField("Click", BindingFlags.NonPublic | BindingFlags.Instance);
    if (eventClickField != null)
    {
        if (_interceptedClickEventHandlers == null)
        {
            _interceptedClickEventHandlers = new Dictionary<Control, EventHandler>();
        }

        // Get the original event and store it against the control for actioning later
        EventHandler eventClick = (EventHandler)eventClickField.GetValue(control);
        _interceptedClickEventHandlers.Add(control, eventClick);

        // Unsubscribe the old event and assign the interception event
        control.Click -= (EventHandler)eventClick;
        control.Click += new EventHandler(UIPanel_ChildClick);
    }

    // Recurse the event subscription operation
    foreach (Control child in control.Controls)
    {
        RecursivelySubscribeChildEvents(child);
    }
}

private void UIPanel_ChildClick(object sender, EventArgs e)
{
    EventHandler interceptedHandler = _interceptedClickEventHandlers[(Control)sender];
    if (interceptedHandler != null)
    {
        // Fire the originally subscribed event if the panel is not scrolling
        if (!_isScrolling)
        {
            interceptedHandler(sender, e);
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM