0

背景:

最初用 .NET 1.1 编写的 WinForms 应用程序通过 Visual Studio 迁移到 .NET 4.0。主应用程序窗体顶部的典型菜单栏(注意:未迁移到 ToolStripMenuItem),正如您可能期望的那样,有一个包含退出菜单项的文件菜单项。

我已经实现了 Ctrl-L 快捷方式,它会弹出一个模式锁定表单。我在主窗体上还有一个计时器组件,如果在可配置的时间段内没有活动,它会自动调出锁定窗体。

当显示锁定表单时,您可以解锁(要求用户重新登录)或退出。如果您选择退出,那么我的代码会调用 fileExitMenuItem.PerformClick()。

问题:

迁移后出于某种奇怪的原因,如果我退出自动显示或由于 Ctrl-L 快捷方式显示的锁定表单,那么我会在 fileExitMenuItem.PerformClick() 代码行上抛出 NullReferenceException。

fileExitMenuItem 不为空;打开 break-when-exception-thrown 后,我可以浏览所有 fileExitMenuItems 属性。

我可以中断表单的设计器代码并观察附加的单击事件处理程序。如果我直接使用 File >> Exit 菜单项,我可以中断事件处理程序中的代码。

所以这是一个完全的WTF时刻。任何关于看什么的建议将不胜感激

[更新 1] 这里要求的是一些代码 - 每当用户按下 Ctrl-L 或锁定计时器结束时都会调用此方法:

private void LockApplication()
    {
        try 
        {
            // Stop the timer so we don't get any more elapsed events whilst we are waiting
            // for a user to respond to the lockdown dialog. In addition stop the callout reminder
            // time as once we have locked we don't want that doing it's thing.
            lockdownTimer.Stop();
            calloutsReminderTimer.Stop();

            // Clone the current identity so we can check it later.
            var previousIdentity = (CudosIdentity)BOUtilities.CurrentIdentity.Clone();

            // Show lockdown form.
            System.Windows.Forms.DialogResult result;
            using (var lockForm = new Forms.applicationLockedForm())
                result = lockForm.ShowDialog(this);

            if (result == DialogResult.OK)
            {
                // Did we unlock with a different login?
                if (!previousIdentity.Equals(BOUtilities.CurrentIdentity))
                {
                    // Yes, so lose all changes.
                    CloseOpenForms();
                    if (_currentLoadSpec != null)
                        _currentLoadSpec.CancelContent();
                }

                RefreshLockTimerSetting(null);
            }
            else
                fileExitMenuItem.PerformClick();
        }
        catch (Exception ex)
        {
            Helper.LogError(ex);
        }
        finally
        {
            lockdownTimer.Start();
            calloutsReminderTimer.Start();
        }
    }

这是退出菜单项的代码:

private void fileExitMenuItem_Click(object sender, System.EventArgs e)
    {
        Application.Exit();
    }

当从上面调用 LockApplication 方法中的以下行时,我得到 NullReferenceException:

fileExitMenuItem.PerformClick();

[更新 2] 执行上述行时调用堆栈信息:

    [External Code] 

Cudos.exe!Cudos.mainForm.LockApplication() 第 1132 行 + 0x10 字节 C# Cudos.exe!Cudos.mainForm.fileLockCudosMenuItem_Click(object sender, System.EventArgs e) 第 1594 行 + 0x8 字节 C# [外部代码] Cudos.exe!Cudos .mainForm.Main() 第 1880 行 + 0x1d 字节 C# [外部代码]

4

2 回答 2

0

我不确定,但如果您调用 Perform_Click,我会尝试删除计时器的重新启动。
当没有更多应用程序时,可以调用 Tick 事件,因为您调用了 Application.Exit()。

private void LockApplication()
{
    try 
    {
        lockdownTimer.Stop();
        calloutsReminderTimer.Stop();

        .....

        if (result == DialogResult.OK)
        {
            ......
            lockdownTimer.Start();
            calloutsReminderTimer.Start();
        }
        else
            fileExitMenuItem.PerformClick();
    }
    catch (Exception ex)
    {
        Helper.LogError(ex);
        lockdownTimer.Start();
        calloutsReminderTimer.Start();
    }
    // remove the finally clause

}
于 2013-06-09T16:44:26.947 回答
0

最后我放弃了,只是通过将 fileExitMenuItem.PerformClick() 更改为 Application.Exit() 来破解它。所以我仍然不知道为什么它会抛出异常,但它至少现在可以工作了。我想如果我将更多逻辑放入 fileExitMenuItem 单击处理程序中,我只需要记住将其提取到一个方法中并更新此 hack 以调用该方法。

于 2013-07-11T10:47:33.040 回答