I have a WPF UserControl in which I try to implement the custom MouseClick (because there is no MouseClick
event on a WPF (User)Control) event.
I got the following:
Some code:
/// <summary>
/// Occurs when users left clicks the MyControl.
/// </summary>
public event MouseButtonEventHandler MouseClick { add { AddHandler(MouseClickEvent, value); } remove { RemoveHandler(MouseClickEvent, value); } }
protected virtual void OnMouseClick(MouseButtonEventArgs e)
{
base.RaiseEvent(e);
//this.RaiseEvent(new RoutedEventArgs(MouseClickEvent, this));
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
if (!this.movedAfterMouseDown)
{
OnMouseClick(e);
}
this.gotLeftButtonDown = false;
this.movedAfterMouseDown = false;
}
So, where is the problem?
protected virtual void OnMouseClick(MouseButtonEventArgs e)
{
//base.RaiseEvent(e);
MouseButtonEventArgs args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, e.ChangedButton);
this.RaiseEvent(args);
}
Value cannot be null. Parameter name: routedEvent
An other custom event I implemented successfully (work without problems) - SelectedChanged
:
static void OnIsSelectedChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
var s = (MyControl)source;
s.RaiseEvent(new RoutedEventArgs(SelectedChangedEvent, s));
}
System.Windows.Controls.Control's OnPreviewMouseDoubleClick implementation:
protected virtual void OnPreviewMouseDoubleClick(MouseButtonEventArgs e)
{
base.RaiseEvent(e);
}
class Foo : FrameworkElement
{
event EasterCameEvent; // I named it MouseClick
public DoSomething()
{
EasterCameArgs args= ...
if (Date.Now = EasterDate)
OnEasterCame(args)
}
protected virtual void OnEasterCame(EasterCameArgs e)
{
base.RaiseEvent(e);
}
}
protected virtual void OnMouseClick(MouseButtonEventArgs e)
{
MouseButtonEventArgs args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, e.ChangedButton);
// Don't forget this
args.RoutedEvent = MouseClickEvent;
base.RaiseEvent(args);
}
You need to remove the base.RaiseEvent(e) from ALL parts of your custom user control. That is the cause of the stack overflow.
If you're inheriting from UserControl, the click events are already implemented for you. You do NOT need to re-implement. You MAY need to handle them though, but most probably you do not.
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
// handle the event if you need to do something with the data.
// this is not over-riding the event, this is attaching a custom handler to the event
this.gotLeftButtonDown = false;
this.movedAfterMouseDown = false;
}
This does not over-ride the event. This is a handler for when the event is raised! Users of your control will write handlers just like this one. Don't reimplement it. Don't even handle it unless you need to do something with the data. These events are written for you already.
Edit:
While my answer was wrong in that it didn't fix the issue, it should still be helpful to understand WHY the stackoverflow exception was happening.
protected virtual void OnMouseClick(MouseButtonEventArgs e)
{
base.RaiseEvent(e);
/* this will raise the OnMouseLeftButtonUp event if the MouseButtonEventArgs
designates that it came from the MouseLeftButtonUp event.
That will then call the OnMouseLeftButtonUp because e.RoutedEvent equals
MouseLeftButtonUpEvent.
The accepted answer does the following, to stop OnMouseLeftButtonUp being
called again, and the whole process repeating itself in an infinite loop.
args.RoutedEvent = MouseClickEvent;
base.RaiseEvent(e); // No longer fires MouseLeftButtonUp, breaking cycle.
// Changes the event to be fired, avoiding the cycle of
// OnMouseLeftButtonUp -> OnMouseClick -> OnMouseLeftButtonUp etc
*/
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
if (!this.movedAfterMouseDown)
{
OnMouseClick(e); // This will call OnMouseClick handler
}
this.gotLeftButtonDown = false;
this.movedAfterMouseDown = false;
}
The control flow was:
The accepted answer changes to this:
This is what I was trying to explain in comments on other answers. If I wasn't clear enough I apologise for that. I believe that serhio and I were out of sync in that I was trying to explain the cause of the stackvoverflow, when he was looking for a fix to the code. Correct me if I'm wrong.
I think it's in this line:
base.RaiseEvent(e);
If you are handling the mouse click you don't want to raise the event again as that will simply call your handler again, which will raise the event....
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With