C# 不在C中执行方法的动态用户控件事件#

C# 不在C中执行方法的动态用户控件事件#,c#,events,user-controls,dynamic-usercontrols,C#,Events,User Controls,Dynamic Usercontrols,我正在努力弄清楚为什么我的用户控件事件没有执行。我有一个动态用户控件“MainMenu”,在一个动态用户控件“MainControl”中 在主菜单中,我有以下内容: public partial class MainMenu : UserControl { public MainMenu() { InitializeComponent(); /// ///Event Subscriptions ///

我正在努力弄清楚为什么我的用户控件事件没有执行。我有一个动态用户控件“MainMenu”,在一个动态用户控件“MainControl”中

在主菜单中,我有以下内容:

public partial class MainMenu : UserControl
{
    public MainMenu()
    {
        InitializeComponent();

        ///
        ///Event Subscriptions
        /// 
        this.LostFocus += this.MainMenu_LostFocus;
    }

    public void MainMenu_LostFocus(object sender, EventArgs e)
    {
        this.Visible = false;
    }
}
在主控制中:

public partial class MainControl : UserControl
{
    private Custom_UI.MainMenu mainMenu = new Custom_UI.MainMenu();
    public MainControl()
    {
        InitializeComponent();
        mainMenu.Visible = false;
        mainMenu.BringToFront();            
        this.Controls.Add(mainMenu);
        mainMenu.BringToFront();
    }
    private void menuButton1_Click(object sender, EventArgs e)
    {
        if (mainMenu.Visible)
        {
            mainMenu.Visible = false;                
        }
        else
        {
            mainMenu.Visible = true;
            this.Focus();
        }
    }
}
最后是主要形式:

public partial class Form1 : Form
{
    MainControl mainControl = new MainControl() {
        Dock = DockStyle.Fill
    };
    public Form1()
    {
        InitializeComponent();
        this.Controls.Add(mainControl);
    }
}
因此,基本上,当我在表单的其他地方单击时,不会调用方法
main menu\u LostFocus
。我还尝试使用
this.MouseLeave
而不是
this.LostFocus


希望这一点我已经足够清楚了,并提前表示感谢。

使用焦点/焦点丢失等方法总是很棘手的。我的建议是稍微修改一下代码

首先,您的
主菜单需要获得焦点才能丢失它

其次,要失去它,另一个控件需要获得焦点-这需要由您来处理(只需单击
MainControl
将不起作用,您需要强制它)

试试这个:

public partial class MainControl : UserControl
{
    private Custom_UI.MainMenu mainMenu = new Custom_UI.MainMenu();
    public MainControl()
    {
        InitializeComponent();
        mainMenu.Visible = false;
        mainMenu.BringToFront();            
        this.Controls.Add(mainMenu);
        mainMenu.BringToFront();
        this.Click += me_Click;
    }

    private void me_Click(object sender, EventArgs e)
    {
        this.Focus(); //this will cause main control to get control (if main menu is focused it'll lose focus and handle it's focus lost and set visible to false in result
    }

    private void menuButton1_Click(object sender, EventArgs e)
    {
        if (mainMenu.Visible)
        {
            mainMenu.Visible = false;   // this should work anyway
        }
        else
        {
            mainMenu.Visible = true;
            mainMenu.Focus(); //when showing mainMenu set focus to it
        }
    }
}

好的。。。以免尝试另一种改进的方法。原因是我们不希望被强制处理添加到
MainControl
的每个控件并强制其接收焦点。这太笨拙了

我们还希望将整个代码封装在一个控件中(
main menu
)-不是“必须拥有”,而是“拥有很好”

这是我的新想法:

 public partial class MainMenu : UserControl
    {

        //this class will be checking native windows messages, the one we're interested in is "MouseDown" with 0x0201 code 
        //(i won't be describing the whole stuff what is going inside: have that checked if you wish in documentation :)

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public class TestMessageFilter : IMessageFilter
        {
            const int WM_MOUSEMOVE = 0x200;
            const int WM_LBUTTONDOWN = 0x0201;

            public event EventHandler MouseMoved;
            public event EventHandler MouseDown;

            public bool PreFilterMessage(ref Message m)
            {
                // Blocks all the messages relating to the left mouse button.
                if (m.Msg == WM_LBUTTONDOWN)
                {
                    MouseDown?.Invoke(this, new EventArgs());
                }
                return false;
            }
        }


        public MainMenu()
        {
            InitializeComponent();

            //use our class that checks Windows Messages, subscribe it's event
            var tmf = new TestMessageFilter();
            tmf.MouseDown += UserControl1_MouseDown;
            //and add our class to Application's messages filter.
            Application.AddMessageFilter(tmf);

            //use "ordinary" events to detect mouse enter/mouse leave over control
            this.MouseLeave += UserControl1_MouseLeave;
            this.MouseEnter += UserControl1_MouseEnter;
        }

        private void UserControl1_MouseDown(object sender, EventArgs e)
        {
            //if mouse is not over control make it's visible false
            if (mouseLeft)
            {
                this.Visible = false;
            }
        }

        //variable to save mouse state (if that is over the control, or left)
        private bool mouseLeft;

        private void UserControl1_MouseEnter(object sender, EventArgs e)
        {
            mouseLeft = false;
        }


        private void UserControl1_MouseLeave(object sender, EventArgs e)
        {
            mouseLeft = true;
        }

    }

希望此解决方案更好、更实用

,这是有意义的。我猜“me_Click”只会被该控件调用,而不会被其子控件调用。您认为无论我单击哪个控件,都有一种简单的方法来调用它吗?或者我必须将该方法添加到所有其他控件及其子控件吗?是的。默认情况下,所有未在单击时获得焦点的控件(标签、面板将无法获得焦点;文本框或按钮将无法获得焦点)都需要类似的操作。那当然很烦人。您可以尝试处理添加到主控件的所有控件(添加控件的事件),但这是一个非常肮脏的解决方案。我可能有一个想法(给我15分钟;))似乎如果在“Focus()”之前设置“.Visible=true”,它将调用“main menu\u LostFocus”。我使用了一个新的“技巧”添加了新的答案,多亏了这个技巧,我们可以避免使用聚焦的东西,并基于鼠标左键控制和本机按钮完成消息,我让它工作了,谢谢。我手工做的唯一一件事就是将事件“.MouseLeave”和“.MouseEnter”添加到主菜单的所有子菜单中,否则,如果我单击其中任何一个,就会将“visible”设置为false。我添加了一个递归方法来获取所有子控件,返回一个数组,然后遍历它们来添加事件处理程序。我还没有预见到这一点,很高兴我能帮上忙!