Winforms:仅在添加断点后执行的代码

时间:2014-08-30 12:58:17

标签: c# .net winforms debugging visual-studio-2013

我有这个Winforms代码(在底部)。当我运行它时,会出现一个带有“button1”的表单。我点击按钮,它消失了,然后我按下一个键 - 它应该触发OnKeyDown但没有任何反应。我在MessageBox::Show(...)行添加断点,单击一个键 - 现在断点被点击,显示MessageBox,每次后续按键也会显示MessageBox,即使我删除了断点。

注意:

  • 我在2台运行Visual Studio 2013的计算机上对此进行了测试 project是一个.Net 4.5 Winforms项目。
  • 在开始调试项目后,必须在Visual Studio中设置断点。
  • 在没有调试的情况下运行项目从不显示MessageBox
  • 根据Sriram的说明,在构造函数中设置this.KeyPreview = true会导致始终显示MessageBox。虽然我仍然不明白为什么设置断点会导致为该调试会话显示MessageBox。

public partial class Form1 : Form
{
    public Form1()
    {
        button1 = new Button();
        button1.Location = new Point(197, 13);
        button1.Name = "button1";
        button1.Text = "button1";
        button1.Click += button1_Click;
        Controls.Add(button1);
        Name = "TestForm";
        KeyDown += OnKeyDown;
    }

    private static void OnKeyDown(object sender, KeyEventArgs keyEventArgs)
    {
        MessageBox.Show("This is shown only after a breakpoint is set on this line");
    }

    private void button1_Click(object sender, EventArgs e)
    {
        button1.Visible = false;
    }

    private readonly Button button1;
}

3 个答案:

答案 0 :(得分:2)

它与设置断点没有任何关系。这种行为是由断点点击时发生的其他事件引起的:窗口被取消激活。在与您的应用程序相同的计算机上运行调试器的不可避免的副作用。当您恢复运行时,窗口会重新激活。现在你看到Winforms中的兼容性代码的副作用使得UI的行为与它的前任(VB6)相同,它会更加积极地将一些控件转换为抓住焦点。

请注意,按Alt + Tab切换到另一个窗口时会出现完全相同的行为。再次按Alt + Tab切换回来。

解释这是一个相当长的故事,我会尽量保持冷凝。焦点在GUI中是一个大问题,键击被发送到当前具有焦点的窗口。拥有它的线程中只能有一个窗口。或者没有。这样的窗口应该是用于处理焦点的窗口类型。它应该指示它,通常使用焦点矩形或插入符号,有时是不同的颜色。当然,用关键笔划做一些有意义的事情。当然你知道它们,Button,TextBox,ListBox等等。

Form类不是其中之一。它是容器控件,是可以获得焦点的控件的主页。非常非常不愿意关注焦点。通过其控件样式重新强制,它关闭了ControlStyles.Selectable,打开了ControlStyles.ContainerControl。容器控件的其他示例是Panel,UserControl,ToolStrip,GroupBox。

因此,当您将按钮的Visible属性设置为 false 时,Winforms需要找到另一个控件来提供焦点。没有留下,它放弃了,没有焦点窗口了。重新激活窗口时,VB6兼容性启动,表单 获得焦点。

只有一个的原因,容器控件应该对键击感兴趣,它应该使用它们来实现快捷键击。像Alt + F4关闭一个窗口,F1显示帮助,Alt + F激活文件菜单,等等。无论哪个控件都有焦点,击键都应该有效。请注意,您获得的常见建议是使用表单的KeyPreview属性,这是另一个麻烦的VB6兼容性属性。它不适用于所有击键,并且特定于表格。

正确的方法是override the ProcessCmdKey() method

答案 1 :(得分:1)

问题在于,当您单击按钮时,即使将其隐藏在代码中,它也会获得并保持焦点。留下断点并返回到您的应用程序是骗人的,因为关键步骤实际上只是将焦点返回到表单(以便其KeyDown处理程序触发)。您只需切换到任何其他应用程序然后返回到表单即可完成此工作。

将KeyPreview设置为true意味着表单会“查看”发往其他窗口控件(如按钮)的事件。当按钮具有焦点时,表单否则看不到keydown事件 - 而是指向按钮。

转向更现代的WPF框架的一个重要原因是,当您拥有深层复杂的组件层次结构时,它可以更好地处理此类事件。集中处理程序变得更加容易。

答案 2 :(得分:0)

这项工作可以帮助你

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
        //your code
        return base.ProcessCmdKey(ref msg, keyData);
    }