Is there a way to capture the Click event of a Button from the parent Control and prevent it occuring if a variable within the parent Control is true?
For example:
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
}
}
Hopefully there's a nicer way to do this than the above example. Just to note, I don't have any control over the events assigned to the afforementioned buttons. They're subscribed elsewhere and I just need to prevent them happening if a variable is true on the consuming parent Control.
My real scenario:
I'm using Windows Mobile 6.5 (legacy application rewrite) I've created a panel control that can contain N number of child controls. The panel control allows for iPhone style vertical scrolling. I subscribe to the MouseMove
event of the child Control
and set a variable _isScrolling
to true
. In the MouseUp
event I set _isScrolling
to false
.
As Click
occurs before MouseUp
I can check within the Click
event to ensure a scroll hadn't occured when the button was pressed. So basically, if a scroll of my panel occurs, I need to prevent the Click event (subscribed at design time) from firing.
This might provide some useful insight
How to remove all event handlers from a control
Specifically, look at
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]);
}
As an alternate way to look at the problem, why not just Subclass the hosting form and look for clicks on your targets. If your preventClick
is true, then mark the message as handled to prevent it from getting passed to the child.
What about disabling buttons instead of setting variable within the parent Control to true?
UPDATE: Setting button.Enabled = false
definitely will prevent from Click event raising :)
UPDATE 2 (for real scenario): consider creating custom button
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);
}
}
Just replace default buttons with scrollable buttons.
Thanks to Hehewaffles answer , here's the solution I came up with:
/// <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);
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.