我们最近升级到了VS 2012,同时还升级了.NET Framework 4.5。这引入了与WinForms MenuStrip控件有关的奇怪且令人讨厌的错误。在以.NET Framework 4.0为目标的应用程序中也会发生相同的错误,因为4.5的安装程序显然也会更新4.0的某些部分。因此,由于框架升级,一个完美工作的代码模式现在被破坏了。

问题描述:
我有一个带有MenuStrip的Form1。对于其中一个下拉项,事件处理程序将打开另一个Form2(不一定是 child ,而是另一个Form)。如果用户右键单击新的Form2或其子控件之一,并触发ContextMenuStrip的Show(),则原始Form1再次弹出到前台。
这独立于Form2中所有其他先前的UI Action 而发生。可以调整Form2的大小,移动,最小化,最大化Form2,在控件之间切换,输入文本等。Form1的MenuStrip似乎以某种方式记得它引起Form2的打开并捕获了第一次右键单击的焦点。

我正在尝试不同的方法,但到目前为止仍无法找到解决方法。这个星座并不罕见,并且可能会影响周围的许多WinForms应用程序。因此,我决定将其发布在这里,因为可行的解决方案可能会引起人们的普遍关注。如果有人知道解决方法或至少对我有一些提示,我将感到非常高兴。

我能够在以下代码中提取其实质。在安装了.NET 4.5的任何计算机上,它都应可重现,并且在将目标分别为4.0和4.5时会发生,但在3.5或更低版本上则不会。

using System;
using System.Windows.Forms;

namespace RightClickProblem {
    static class Program {
        [STAThread]
        static void Main() {
            // Construct a MenuStrip with one item "Menu" with one dropdown-item "Popup"
            var mainMenu = new MenuStrip();
            var mainItem = new ToolStripMenuItem("Menu");
            mainItem.DropDownItems.Add(new ToolStripMenuItem("Popup", null, Popup));
            mainMenu.Items.Add(mainItem);

            // Create form with MenuStrip and Show
            var form1 = new Form();
            form1.Controls.Add(mainMenu);
            Application.Run(form1);
        }

        private static void Popup(object sender, EventArgs e) {
            // Create a form with a right click handler and show
            var form2 = new Form();
            var contextMenu = new ContextMenuStrip();
            contextMenu.Items.Add("Just an item...");
            form2.ContextMenuStrip = contextMenu;
            form2.Show();
            // Problem: contextMenu.Show() will give focus to form1
        }
    }
}

编辑:我花了一些时间逐步浏览.NET Framework源代码,发现根本原因很可能出现在System.Windows.Forms.ToolStripManager中。在那里,Microsoft使用消息过滤器来跟踪窗口激活,该窗口激活在某种程度上不正确地用于MenuStrip。
同时,我还发现Microsoft已经在修复程序中解决了此问题(请参阅http://support.microsoft.com/kb/2769674),并希望这将在以后的.NET Framework 4.5更新中找到解决方法。

不幸的是,很难在所有客户端计算机上强制应用此修补程序。因此,仍将不胜感激可行的解决方法。到目前为止,我本人仍无法找到切实可行的解决方案。

编辑#2:原始KB号用于Win8,但在KB 2756203下有类似的Win7和Vista修补程序。如果有人可以使用,请在此处找到可下载的修补程序:http://thehotfixshare.net/board/index.php?autocom=downloads&showfile=15569。我们对其进行了测试,它确实解决了该问题。如果我们很快发现绝对没有解决方法,我们将使用此修复程序。

编辑#3:注释spajce 提出的已接受解决方案
显然,在任何ContextMenu上调用Show()都会说服原始MenuStrip忘记其对焦点的要求。这可以通过某种方式完成,以使虚拟ContextMenu甚至不会显示在屏幕上。我发现了在任何Form的构造函数中插入以下代码段的最短,最容易实现的方法:
public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();

        using (var dummyMenu = new ContextMenuStrip()) {
            dummyMenu.Items.Add(new ToolStripMenuItem());
            dummyMenu.Show(Point.Empty);
        }
    }
}

因此,每个打开的Form都会清理ToolStripMenu系统的损坏状态。最好将这段代码放在诸如FormHelper.FixToolStripState()之类的静态方法中,或者将其放在模板Form的OnCreateControl(...)中,并从中继承所有Forms(无论如何,我们很幸运地做到了)。

最佳答案

这是我的解决方案:)

 static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // Construct a MenuStrip with one item "Menu" with one dropdown-item "Popup"
            var mainMenu = new MenuStrip();
            var mainItem = new ToolStripMenuItem("Menu");
            mainItem.DropDownItems.Add(new ToolStripMenuItem("Popup", null, Popup));
            mainMenu.Items.Add(mainItem);

            // Create form with MenuStrip and Show
            var form1 = new Form();
            form1.Controls.Add(mainMenu);
            Application.Run(form1);
        }

        private static void Popup(object sender, EventArgs e)
        {
            // Create a form with a right click handler and show
            var form2 = new Form();
            var contextMenu = new ContextMenuStrip();
            contextMenu.Items.Add("Just an item...");
            var loc = form2.Location; //<---- get the location
            var p2 = new Point(loc.X, loc.Y); //<---- get the point of form
            form2.ContextMenuStrip = contextMenu;
            form2.ContextMenuStrip.Show(form2, p2); //<---- just add this code.
            form2.Show();
            // Problem: contextMenu.Show() will give focus to form1
        }
    }

关于c# - .NET 4.0/4.5 WinForms MenuStrip窃取焦点的奇怪错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14058222/

10-10 23:26