none
Hooking multiple events to one action RRS feed

  • Question

  • I am trying to display the same message box (TotalAngleofRing) when the Right MouseButton is clicked on several different objects on a form. I can do this without any trouble as I have shown in the attached code. However, I need to do this for quiet a few different controls and I'm wondering if there is an easier way than rewriting the same code over and over. Any suggestions would be appreciated. 

      private void txtTotAngle_MouseDown(object sender,MouseEventArgs e)
    		  {
    				if (e.Button==MouseButtons.Right)
    				{
    					 TotalAngleofRing ( );
    				}
    		  }
    
    		  private void lblTotallAngle_MouseDown(object sender,MouseEventArgs e)
    		  {
    				if (e.Button==MouseButtons.Right)
    				{
    					 TotalAngleofRing ( );
    				}
    		  }


    JR

    Tuesday, January 22, 2019 7:45 AM

Answers

  • Hi J_Reid,

    Thank you for posting here.

    Based on your description, you want to display the same message box for different controls with easier way.

    You could try the following code.

    private void Form1_Load(object sender, EventArgs e)
            {
                foreach (Control item in this.Controls)
                {
                    item.MouseDown += way;
                }
            }
    
            private void way (object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Right)
                {
                    TotalAngleofRing();
                }
            }
            public void TotalAngleofRing()
            {
                MessageBox.Show("success");
            }
    
    Result:

    Hope my advice could be helpful.

    Best regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by J_Reid Wednesday, January 23, 2019 1:29 AM
    Tuesday, January 22, 2019 9:27 AM
    Moderator
  • Hello,

    If you need to be selective as in only have say labels and text box controls subscribing to MouseDown event and or the targeted controls may also be in other containers e.g. in a group box then the following may be of assistance.

    VS2017 sample project on Microsoft Onedrive.

    In green are all setup for mouse down while the other controls are not. 

    Add the class below to your project where the extension Descendants given a specific type of control for a container (in this case a form but could also target say a panel or groupbox etc) iterates all controls and sibling controls (as in the case from the image above which contains a group box) and returns what has been asked for. 

    using System.Collections.Generic;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp1 // change to your namespace
    {
        public static class WindowsControlsExtensions 
        {
            public static IEnumerable<T> Descendants<T>(this Control control) where T : class
            {
                foreach (Control child in control.Controls)
                {
    
                    T childOfT = child as T;
                    if (childOfT != null)
                    {
                        yield return (T)childOfT;
                    }
    
                    if (child.HasChildren)
                    {
                        foreach (T descendant in Descendants<T>(child))
                        {
                            yield return descendant;
                        }
                    }
                }
            }
        }
    }

    Example of how to use

    using System;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                Shown += Form1_Shown;
            }
    
            private void Form1_Shown(object sender, EventArgs e)
            {
                this.Descendants<TextBox>().ToList().ForEach(tb => 
                    tb.MouseDown += SharedMouseDownEvent);
    
                this.Descendants<Label>().ToList().ForEach(lb => 
                    lb.MouseDown += SharedMouseDownEvent);
            }
            private void SharedMouseDownEvent(object sender, MouseEventArgs e) 
            {
                if (e.Button == MouseButtons.Right)
                {
                    TotalAngleofRing();
                }
            }
            public void TotalAngleofRing() => 
                MessageBox.Show("success");
        }
    
    }


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites


    Tuesday, January 22, 2019 10:44 AM
    Moderator
  • If one entry goes along with a prior entry then it seems that the first place to start is with a naming convention of the labels and text box controls so that in the TotalAngleOfRing you have a reference point. So then in the method you would have additional logic based on what control was passed to it.

    Conceptual example TextBox is named TextBoxKaren2 and the logic is to peek at another one say TextBoxKaren1 logic would get Karen2 and "know" to search for a TextBox with Karen in it and ending in 1. My first thought is to utilize regular expressions. Yet another thought is to store information in the Tag property of these controls were whatever makes sense can go there as Tag is an Object so it can be a int, string, an instance of a class where members in the class point to other object e.g. a label or Textbox etc.

    private void SharedMouseDownEvent(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Right)
        {
            TotalAngleofRing((Control)sender);
        }
    }
    
    public void TotalAngleofRing(Control sender)
    {
        switch (sender)
        {
            case TextBox _:
                break;
            case Label _:
                break;
        }
    }
    I could write a code sample based on the above but really don't have time too as I would hate to put together a not fully complete example as that is not in my nature.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    • Marked as answer by J_Reid Wednesday, January 23, 2019 3:56 AM
    Wednesday, January 23, 2019 2:56 AM
    Moderator

All replies

  • Hi J_Reid,

    Thank you for posting here.

    Based on your description, you want to display the same message box for different controls with easier way.

    You could try the following code.

    private void Form1_Load(object sender, EventArgs e)
            {
                foreach (Control item in this.Controls)
                {
                    item.MouseDown += way;
                }
            }
    
            private void way (object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Right)
                {
                    TotalAngleofRing();
                }
            }
            public void TotalAngleofRing()
            {
                MessageBox.Show("success");
            }
    
    Result:

    Hope my advice could be helpful.

    Best regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by J_Reid Wednesday, January 23, 2019 1:29 AM
    Tuesday, January 22, 2019 9:27 AM
    Moderator
  • Hello,

    If you need to be selective as in only have say labels and text box controls subscribing to MouseDown event and or the targeted controls may also be in other containers e.g. in a group box then the following may be of assistance.

    VS2017 sample project on Microsoft Onedrive.

    In green are all setup for mouse down while the other controls are not. 

    Add the class below to your project where the extension Descendants given a specific type of control for a container (in this case a form but could also target say a panel or groupbox etc) iterates all controls and sibling controls (as in the case from the image above which contains a group box) and returns what has been asked for. 

    using System.Collections.Generic;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp1 // change to your namespace
    {
        public static class WindowsControlsExtensions 
        {
            public static IEnumerable<T> Descendants<T>(this Control control) where T : class
            {
                foreach (Control child in control.Controls)
                {
    
                    T childOfT = child as T;
                    if (childOfT != null)
                    {
                        yield return (T)childOfT;
                    }
    
                    if (child.HasChildren)
                    {
                        foreach (T descendant in Descendants<T>(child))
                        {
                            yield return descendant;
                        }
                    }
                }
            }
        }
    }

    Example of how to use

    using System;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                Shown += Form1_Shown;
            }
    
            private void Form1_Shown(object sender, EventArgs e)
            {
                this.Descendants<TextBox>().ToList().ForEach(tb => 
                    tb.MouseDown += SharedMouseDownEvent);
    
                this.Descendants<Label>().ToList().ForEach(lb => 
                    lb.MouseDown += SharedMouseDownEvent);
            }
            private void SharedMouseDownEvent(object sender, MouseEventArgs e) 
            {
                if (e.Button == MouseButtons.Right)
                {
                    TotalAngleofRing();
                }
            }
            public void TotalAngleofRing() => 
                MessageBox.Show("success");
        }
    
    }


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites


    Tuesday, January 22, 2019 10:44 AM
    Moderator
  • Karen,

    I really appreciate your response and even more so the sample project. Your coding skill level is well above mine. I do understand what you have done and how it works and I like the way you went about it. However, I think that I did not state the problem clearly enough. 

    I have a form, or will have when it is finished, that is likely to contain 30 to 40 textboxes and labels. The form is interactive with the user and computes a running total accumulated angle depending on the information entered into each textbox as it is entered. The information entered into each textbox is dependent on the total accumulated angle based on the previous entry.  I hope that makes sense. So I want to be able to right click the textbox or label and check the total accumulated angle before each entry. I do not want to display this message box for all textboxes or labels only for the ones that are applicable, probably 6 to 8 of them. The other textboxes and labels have different message boxes associated with each of them. I think I can combine part of what Jack offered in his response with part of what you have shown me here to come up with a solution to my problem. Please feel free to offer any additional suggestions you feel like offering. 

    Again thanks very much for your response.


    JR

    Wednesday, January 23, 2019 1:29 AM
  • Jack,

    Thanks for your response. This is not quite what I was looking for but that was not your fault. I should have been a little more specific with my question. See my response to Karen to explain my problem a little better. I am going to combine some of your response with some of Karen's response to try to get what I need. If you have any further suggestions I would love to here them. Thanks again.


    JR

    Wednesday, January 23, 2019 1:34 AM
  • If one entry goes along with a prior entry then it seems that the first place to start is with a naming convention of the labels and text box controls so that in the TotalAngleOfRing you have a reference point. So then in the method you would have additional logic based on what control was passed to it.

    Conceptual example TextBox is named TextBoxKaren2 and the logic is to peek at another one say TextBoxKaren1 logic would get Karen2 and "know" to search for a TextBox with Karen in it and ending in 1. My first thought is to utilize regular expressions. Yet another thought is to store information in the Tag property of these controls were whatever makes sense can go there as Tag is an Object so it can be a int, string, an instance of a class where members in the class point to other object e.g. a label or Textbox etc.

    private void SharedMouseDownEvent(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Right)
        {
            TotalAngleofRing((Control)sender);
        }
    }
    
    public void TotalAngleofRing(Control sender)
    {
        switch (sender)
        {
            case TextBox _:
                break;
            case Label _:
                break;
        }
    }
    I could write a code sample based on the above but really don't have time too as I would hate to put together a not fully complete example as that is not in my nature.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    • Marked as answer by J_Reid Wednesday, January 23, 2019 3:56 AM
    Wednesday, January 23, 2019 2:56 AM
    Moderator
  • Thanks again!

    What you have shown here is almost exactly what I am working on right now. I've added a little more to this to deal with some other controls but this is essentially what I am doing. I had not thought about your naming convention idea and using regular expressions but I think that is a very good idea and that will make it even easier. Thanks!!!


    JR

    Wednesday, January 23, 2019 4:04 AM