RadioButton Click 事件在启动时错误地触发

RadioButton Click event erroneously fires on startup

编辑: 这是一个与涵盖的问题不同的问题 in this proposed duplicate。该问题解决了一个不同的问题,none 的答案适用于我的情况。我的单选按钮从一开始就被选中,因为它是 supposed。它(或者更确切地说是它的组的成员)在 Load 事件处理程序中使用保存的 属性 设置。另外,如下所述,我麻烦的单选按钮不是 Tab 键顺序中的第一个。

我刚开始在 WinForms 应用程序上遇到问题,我的任务是重构。

在窗体的 Load 事件处理程序完成一段时间后,一个特定单选按钮的 Click 事件会自动触发。我不明白为什么,它打乱了程序的预期流程。

我在click handler的开头打了一个断点,查看了调用栈,但是麻烦的调用总是来自外部代码,最后两行是RadioButton.OnEnter后面是Control.OnClick

谷歌搜索出现 this SE answer,但这与我的情况不太相符。有问题的单选按钮在选项卡顺序中相当靠后,所有控件都是在 VS 设计器中添加的,而不是通过代码添加的,加载处理程序在完成之前将 Focus 设置为 different 控件。在 Load 处理程序的末尾和错误的 Click 之间没有遇到对单选按钮的引用(使用 way too many breakpoints 验证)。

有谁知道还有什么可能导致控件在启动时自动单击?

编辑 这是单选按钮 (mVmOff) 及其所在的嵌套组框的设计器代码:

            // 
            // mVmGroup (6th in tab order)
            // 
            this.mVmGroup.Controls.Add(this.milliVmGroup);
            this.mVmGroup.Controls.Add(this.mVRLabel);
            this.mVmGroup.Controls.Add(this.mVmLabel);
            this.mVmGroup.Controls.Add(this.mVRCombo);
            this.mVmGroup.Controls.Add(this.mVm);
            this.mVmGroup.Font = new System.Drawing.Font("Verdana", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.mVmGroup.ForeColor = System.Drawing.Color.Black;
            this.mVmGroup.Location = new System.Drawing.Point(200, 295);
            this.mVmGroup.Name = "mVmGroup";
            this.mVmGroup.Size = new System.Drawing.Size(169, 140);
            this.mVmGroup.TabIndex = 6;
            this.mVmGroup.TabStop = false;
            this.mVmGroup.Text = "mV Meter";
            this.toolTip.SetToolTip(this.mVmGroup, "This is the Milli Voltmeter\'s matrix.");
            // 
            // milliVmGroup (6.4 in tab order)
            // 
            this.milliVmGroup.Controls.Add(this.mVmOS);
            this.milliVmGroup.Controls.Add(this.mVmOff);
            this.milliVmGroup.Controls.Add(this.mVmIS);
            this.milliVmGroup.Font = new System.Drawing.Font("Verdana", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.milliVmGroup.ForeColor = System.Drawing.Color.RoyalBlue;
            this.milliVmGroup.Location = new System.Drawing.Point(8, 63);
            this.milliVmGroup.Name = "milliVmGroup";
            this.milliVmGroup.Size = new System.Drawing.Size(152, 71);
            this.milliVmGroup.TabIndex = 4;
            this.milliVmGroup.TabStop = false;
            this.milliVmGroup.Text = "Matrix";
            // 
            // mVmOff (6.4.2 in tab order)
            // 
            this.mVmOff.AutoSize = true;
            this.mVmOff.Checked = true;
            this.mVmOff.Font = new System.Drawing.Font("Verdana", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.mVmOff.Location = new System.Drawing.Point(5, 49);
            this.mVmOff.Name = "mVmOff";
            this.mVmOff.Size = new System.Drawing.Size(42, 17);
            this.mVmOff.TabIndex = 2;
            this.mVmOff.TabStop = true;
            this.mVmOff.Text = "Off";
            this.toolTip.SetToolTip(this.mVmOff, "Click to disconnect the Milli Voltmeter. \r\nDisconnects K29, K8, and K30. \r\nConnec" +
        "ts K3 and K11. \r\n \r\nNote: Normaly checked.");
            this.mVmOff.UseVisualStyleBackColor = true;
            this.mVmOff.Click += new System.EventHandler(this.MVmOff_Click);

以及表格该部分的屏幕截图: mV Meter group box

如果有帮助,在错误点击发生的断点处,单选按钮是唯一绘制在窗体上的控件。

一般情况下,您应该依赖 CheckedChange 并仅在发生点击时使用 Click。

但我会回答你的问题:

Does anyone have any idea what else might cause a control to be automatically clicked on startup?

您的 RadioButton 已按预期获得焦点。然后引发 Click 事件是 RadioButton 的 OnEnter 方法中存在的逻辑错误。当您使用箭头键输入控件时,它会尝试引发 OnClick,但它无法以正确的方式执行此操作,例如,即使焦点已在没有箭头键的情况下自动移动到控件,它也会引发 Click 事件。

您可以通过重写 OnEnter 来禁止在进入控件时引发 Click 事件:

using System;
using System.Windows.Forms;
public class MyRadioButton : RadioButton
{
    protected override void OnEnter(EventArgs e)
    {
        RaiseOnEnter(e);
    }
    private void RaiseOnEnter(EventArgs e)
    {
        var EventEvent = typeof(Control).GetField("EventEnter",
        System.Reflection.BindingFlags.NonPublic |
        System.Reflection.BindingFlags.Static).GetValue(null);
        EventHandler handler = (EventHandler)Events[EventEvent];
        handler?.Invoke(this, e);
    }
}

关于 .NET 5 和 6 的注意事项

即使在 .NET 5 and 6 RadioButton 中也有同样的问题;如果您想对这些版本使用上述解决方法,请确保您获得 s_enterEvent 字段。