How to create user define (new) event for user control in WPF ?one small example
Asked Answered
O

3

30

I have one UserControl in which I am using a Canvas, and in that Canvas one Rectangle. I want to create a click event for that user control (Canvas and Rectangle) which I then want to use in the main window.

The question is: I want to create a new click event for the UserControl. How to do it? Kindly show little example or the code.

Oulman answered 19/11, 2012 at 5:2 Comment(1)
This question isn't very clear. Perhaps you could rephrase to clarify what you are asking?Arrive
M
72

A brief example on how to expose an event from the UserControl that the main window can register:

In your UserControl:

1 . Add the following declaration:

public event EventHandler UserControlClicked;

2 . In your UserControl_Clicked event raise the event like this:

 private void UserControl_MouseDown(object sender, MouseButtonEventArgs e)
 {
        if (UserControlClicked != null)
        {
            UserControlClicked(this, EventArgs.Empty);
        }
  }

In your MainWindow:

Your usercontrol will now have a UserControlClicked event which you can register to:

<local:UserControl1 x:Name="UC" UserControlClicked="UC_OnUserControlClicked" />
Massasoit answered 19/11, 2012 at 9:10 Comment(4)
Would you need to unsubscribe this registration?Confucianism
For sake of completeness, the UserControl_MouseDown event also needed to tied to the actual MouseDown event in XAML obviously for this to work.Excel
I can't get this to work. It tells me UserControlClicked is not accessible or not recognized.Predestinarian
@Excel the other possibility is to override the current OnMouseDown handler protected override void OnMouseDown(MouseButtonEventArgs e) and invoking base.OnMouseDown(e) inside.Martita
P
0

i find this easier for passing value to handler:

public event Action<string> onUserCodeFetched;

private void btnEnterClicked(object sender, RoutedEventArgs e)
        {
            onUserCodeFetched(PersonellCode.Text);
            PersonellCode.Text = "";
        }
Pauiie answered 1/5, 2019 at 5:34 Comment(1)
I used to use Actions instead of EventHandlers, then I reconsidered that practice after reading this https://mcmap.net/q/127575/-event-action-lt-gt-vs-event-eventhandler-lt-gtAspinwall
S
0

It's an old question, but I also found useful to bypass the event using a property-like custom event as in here. You can use a general EventHandler or you can be more specific (RoutedEventHandler, MouseButtonEventHandler, etc) to avoid later casts. For instance, to bypass a click event, you could write in your custom control class:

        public readonly object objectLock = new object();
        public event RoutedEventHandler CustomClick
        {
            add{  lock (objectLock) { myClickableInnerControl.Click += value;}}
            remove {lock (objectLock) { myClickableInnerControl.Click -= value; }}
        }

and for a PreviewMouseDown event, it would be something like:

        public readonly object objectLock = new object();
        public event MouseButtonEventHandler CustomPreviewMouseDown
        {
            add{  lock (objectLock) { myInnerControl.PreviewMouseDown += value;}}
            remove {lock (objectLock) { myInnerControl.PreviewMouseDown -= value; }}
        }

Where myInnerControl would be your canvas in this case.

Then you can initialize the event from xaml as

    <local:myClickableControl x:Name="ClickCtrl1" CustomClick="ClickCtrl1_CustomClick" />

or

    <local:myCustomControl x:Name="CustomCtrl1" CustomPreviewMouseDown="CustomCtrl1_CustomPreviewMouseDown" />

And from code behind:

        ClickCtrl1.CustomClick+=ClickCtrl1_CustomClick;

or

        CustomCtrl1.CustomPreviewMouseDown+=CustomCtrl1_CustomPreviewMouseDown;

You can also subscribe your callback to several inner controls events (being careful when they overlap as some events like previewMouseDown are not only fired by the front control but also by the controls underneath).

        public readonly object objectLock = new object();
        public event MouseButtonEventHandler CustomPreviewMouseDown
        {
            add{  lock (objectLock) 
                   { 
                       myInnerControl1.PreviewMouseDown += value;
                       myInnerControl2.PreviewMouseDown += value;
                   }}
            remove {lock (objectLock) 
                    { 
                        myInnerControl1.PreviewMouseDown -= value; 
                        myInnerControl2.PreviewMouseDown -= value; 
                    }}
        }

(If the inner controls partially overlap, you can use the corresponding eventArgs Handled property in your callback method to avoid repetitions)

Finally, you can add a layer of control to the event fired by your inner control:

        bool MousePreviewDownUsed = false;
        event MouseButtonEventHandler _myPreviewMouseDownEvent = null;
        public  event MouseButtonEventHandler CustomPreviewMouseDown
        {
            add
            {
                lock (objectLock)
                {
                    _myPreviewMouseDownEvent += value;

                    if (value != null && !MousePreviewDownUsed)
                    {
                        myInnerControl.PreviewMouseDown += myInnerControl_PreviewMouseDown;
                        MousePreviewDownUsed = true;
                    }
                }
            }
            remove
            {
                lock (objectLock)
                {
                   if (_myPreviewMouseDownEvent != null)
                    {
                        _myPreviewMouseDownEvent -= value;
                        if ((_myPreviewMouseDownEvent == null || 
                             _myPreviewMouseDownEvent.GetInvocationList().Length == 0) 
                              && MousePreviewDownUsed)
                        {
                            _myPreviewMouseDownEvent = null;
                            myInnerControl.PreviewMouseDown -= myInnerControl_PreviewMouseDown;                           
                            MousePreviewDownUsed = false;
                        }
                    }
                }
            }
        }


 
        private void myInnerControl_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            // Do some previous operations or control whether the event must be broadcasted

            _myPreviewMouseDownEvent?.Invoke(sender, e);
        }

This event is initialized from xaml or code behind the same way as before.

Saturnian answered 7/4, 2021 at 18:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.