0

バックグラウンド:

もともと .NET 1.1 で作成され、Visual Studio を介して .NET 4.0 に移行された WinForms アプリ。メイン アプリ フォームの上部にある典型的なメニュー バー (注: ToolStripMenuItem には移行されていません)。Exit メニュー項目を含む File メニュー項目があると予想されるかもしれません。

モーダル ロック フォームを表示する Ctrl-L ショートカットを実装しました。メイン フォームにはタイマー コンポーネントもあり、構成可能な時間のアクティビティがない場合に自動的にロック フォームが表示されます。

ロック フォームが表示されたら、ロックを解除する (ユーザーが再度ログインする必要がある) か、終了することができます。終了することを選択した場合、私のコードは fileExitMenuItem.PerformClick() 呼び出しを行います。

問題:

移行後に何らかの奇妙な理由で、自動的に、または Ctrl-L ショートカットによって表示されたロック フォームを終了すると、コードの fileExitMenuItem.PerformClick() 行で NullReferenceException がスローされます。

fileExitMenuItem は null ではありません。break-when-exception-throw をオンにすると、すべての fileExitMenuItems プロパティを参照できます。

フォームのデザイナー コードを中断して、クリック イベント ハンドラーがアタッチされているのを確認できます。[ファイル] >> [終了] メニュー項目を直接使用すると、イベント ハンドラーのコードを中断できます。

つまり、これは完全な 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 を呼び出すと、タイマーの再起動を削除しようとします。
Application.Exit() を呼び出すため、アプリケーションがなくなったときに Tick イベントを呼び出すことができます。

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 に答える