2

うまくいけば、これに従うのはそれほど難しくありません。

私は現在、バックグラウンドで静かに実行される小さなタイムログ アプリケーションに取り組んでいます。ティッカーが停止するたびに、アプリケーションはユーザーに、最後のプロンプト以降に何をしていたかを尋ねるプロンプトを出します。最終的には、アプリケーションでデータをスプレッドシートに書き込むようにします。

私がこれまでに持っているオプションの 1 つは、ユーザーがデフォルトのプロンプト設定を使用するかどうかを選択できるようにします (プロンプトが見逃されるたびに、次のプロンプトが作成されるまで表示されたままになります。しばらくの間、かなりの数のプロンプトが画面に表示され、入力を待っている可能性があります) またはすべてのプロンプトを結合したい (プロンプトが見逃され、新しいプロンプトがポップアップするたびに、古いプロンプトが表示されます)。閉じられ、新しいプロンプトは古いプロンプトと新しいプロンプトの時間をカバーします)。

ユーザーは、チェックボックスを選択してプロンプトをオフにすることもできます。プロンプトを再度オンにすると、プロンプトがオフになっている間に何をしていたかをユーザーに入力するよう求めるプロンプトがポップアップ表示されます (ユーザーがフルスクリーン アプリケーションを実行している場合などに役立ちます)。

私の問題は、プロンプトを生成しようとすると、正しく表示されないことです。それらをまったく操作できず、コントロールも表示されません。それらは基本的に空のフォームのように見えます。

ティッカーを使用してプロンプトを生成するための私のコードは次のとおりです。

public void ticker(object source, System.Timers.ElapsedEventArgs e)
    {
        if (groupMissed)
        {
            incrementsMissed += 1;
            if (incrementsMissed > 1)
            {
                IncrementForm form = (IncrementForm)Application.OpenForms["IncrementForm"];
                if (form.InvokeRequired)
                {
                    form.Invoke(new MethodInvoker(delegate { form.Close(); }));
                }
            }
        }
        else
        {
            incrementsMissed = 1;
        }

        IncrementForm theIncrementForm = new IncrementForm(this, e.SignalTime);
        theIncrementForm.Show();
        latestIncrement = e.SignalTime;
    }

そして、「プロンプトをオフにする」チェックボックスを使用してプロンプトを生成するための私のコードは次のとおりです。

private void chkbxAlerts_Click(object sender, EventArgs e)
    {
        if (!chkbxAlerts.Checked)
        {
            // Ensures that the time missed is covered and restarts the timer
            DateTime now;
            now = DateTime.Now;
            if ((now - latestIncrement).TotalMinutes >= 1) // Only records time if it is equal to or greater than one minute
            {
                // TO-DO: FIX
                if (groupMissed)
                {
                    incrementsMissed += 1;
                    if (incrementsMissed > 1)
                    {
                        IncrementForm form = (IncrementForm)Application.OpenForms["IncrementForm"];
                        if (form.InvokeRequired)
                        {
                            form.Invoke(new MethodInvoker(delegate { form.Close(); }));
                        }
                    }
                }
                else
                {
                    incrementsMissed = 1;
                }
                IncrementForm theIncrementForm = new IncrementForm(this, now, latestIncrement);
                theIncrementForm.Show();
                latestIncrement = now;
            }
            timer.Enabled = true;
        }
        else
        {
            // Stops the timer
            timer.Enabled = false;
        }
    }

さらに説明が必要な場合は、お知らせください。助けてくれてありがとう、これは私を悩ませてきました。

4

2 に答える 2

2

System.Timers.TimerSynchronizingObjectプロパティがあります。これをメインフォーム(またはタイマーを含むフォーム)に設定すると、GUIスレッドでタイマーティックイベントが発生します。

イベントSystem.Timers.Timerで発生する例外を飲み込むという厄介な習慣があることに注意してください。Elapsedティックハンドラーが例外をスローした場合、それは表示されません。それは厄介なバグハイダーです。そのため、またはのいずれSystem.Windows.Forms.Timerかを使用することをお勧めしますSystem.Threading.Timer。Windowsフォームタイマーを使用する場合、経過イベントはGUIスレッドで発生します。を使用する場合は、NSGagaが彼の回答で示してSystem.Threading.Timerいるように使用する必要があります。Invoke

の使用を推奨しない理由の詳細については、「例外を飲み込むことでバグを隠す」を参照してくださいSystem.Timers.Timer

于 2012-04-19T01:38:18.823 に答える
2

私が見る限り、100%ではなく、タイマーが別のスレッドでウィンドウを生成していると思います(タイマーティッカー呼び出しから)。

理論的には機能しますが (このHow to open a form in a thread and force it to stay open を見てください)
...メインスレッド内にとどまる方がはるかに良い場合があります。

このようなものを試してみてください...

yourMainWindow.Invoke(new MethodInvoker(() =>
    {
        IncrementForm theIncrementForm = new IncrementForm(this, e.SignalTime);
        theIncrementForm.Show();
        latestIncrement = e.SignalTime;
    }));

...それはあなたのタイマーからのものです - そうすれば、(私が見ることができるように) すべてを「メインスレッド上」に置いて、物事をはるかに簡単にする必要があります。

お役に立てれば

于 2012-04-19T01:25:10.417 に答える