When Raising an MouseButtonEvent from a UserControl the MainWindow have no access to MouseButtonEventArgs

2.6k views Asked by At

Still climbing up the steep WPF Mountain, and suffering.

I have defined a UserControl, and my MainWindow needs to retrieve the MouseButtonEventArgs coming from a control inside the UserControl (like the mouse e.GetPosition for instance)

In the UserControl code behind, I have done the Registrations and I Raise the bubbling event.

public static readonly RoutedEvent MyButtonDownEvent = EventManager.RegisterRoutedEvent("MyMouseButtonDown", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyUserControl));
    public event RoutedEventHandler MyButtonDown {
        add { AddHandler(MyButtonDownEvent, value); }
        remove { RemoveHandler(MyButtonDownEvent, value); }
    }
    private void MyMouseButtonDownHandler(object sender, MouseButtonEventArgs e) {
        RaiseEvent(new RoutedEventArgs(MyButtonDownEvent ));
    }

Now in my MainWindow I declare the UserControl like this:

<local:MyUserControl MouseDown="MyUserControl_MouseDown"/>

And this code behind

private void MyUserControl_MouseDown(object sender, RoutedEventArgs e) 

And I receive the events from the UserControl, but the Args are RoutedEventArgs (which is normal) but I dont have access to the MouseButtonEventArgs that I need to get the mouse e.GetPosition.

What elegant solution would you suggest in this case ?

2

There are 2 answers

1
Jean-Marie On BEST ANSWER

I think I finally got it (at least I hope):

If I write in the code behind:

        public event EventHandler<MouseButtonEventArgs> MyRightButtonDownHandler;
    public void MyRightButtonDown(object sender, MouseButtonEventArgs e) {
        MyRightButtonDownHandler(sender, e);
    }

Then in the consumer (MainWindow) XAML:

<local:GlobalDb x:Name="globalDb"  MyRightButtonDownHandler="globalDb_MyRightButtonDownHandler"/>

And in the consumer code behind:

    private void globalDb_MyRightButtonDownHandler(object sender, MouseButtonEventArgs e) {
        Console.WriteLine("x= " + e.GetPosition(null).X + " y= " + e.GetPosition(null).Y);
    }

Please tell me if you have a better solution (By design policy - rules established where I work - all the event handling of my application MUST appear in the XAML).

Thanks again for your help,

6
brunnerh On

Why do you define your own MouseDown event while UserControl already has a normal MouseDown event?

Anyway, if you define an event to use a RoutedEventHandler it is hardly surprising that you'll end up being stuck with a RoutedEventHandler. You declared it like this:

public static readonly RoutedEvent MyButtonDownEvent = EventManager.RegisterRoutedEvent("MyMouseButtonDown", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyUserControl));

Notice the bit where it says typeof(RoutedEventHandler)?

If i am not mistaken your code should look like this instead:

    public static readonly RoutedEvent MyButtonDownEvent =
        EventManager.RegisterRoutedEvent
        ("MyButtonDown",
        RoutingStrategy.Bubble,
        typeof(MouseButtonEventHandler),
        typeof(MyUserControl));

    public event MouseButtonEventHandler MyButtonDown
    {
        add { AddHandler(MyButtonDownEvent, value); }
        remove { RemoveHandler(MyButtonDownEvent, value); }
    }

Example of how to propagate an existing MouseDown event to the custom event:

InitializeComponent();
this.MouseDown += (s, e) => {
    RaiseEvent(new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, e.ChangedButton)
                    { 
                        RoutedEvent = MyButtonDownEvent
                    });
};