0

私はこのコードを持っています:

 private void Form1_Load(object sender, EventArgs e)
        {
            /*start update timer*/
            System.Timers.Timer updateticker = new System.Timers.Timer();
            updateticker.Elapsed += new ElapsedEventHandler(update_overload);
            //10 minute ticker
            updateticker.Interval = 600000;
            //30 sec ticker
            updateticker.Interval = 30000;
            updateticker.Enabled = true;

            System.Timers.Timer guiTimer = new System.Timers.Timer();
            guiTimer.Elapsed += new ElapsedEventHandler(idle_display);
            //1 minute ticker
            guiTimer.Interval = 60000;
            //30 sec ticker
            //updateticker.Interval = 30000;
            guiTimer.Enabled = true;

        }

 //run front end idle timer
        public void idle_display(object source, ElapsedEventArgs e)
        {
            if (minutes_left > 0) {
                minutes_left = minutes_left - 1;
            }

            lbl_dyn_status.Text = "Time until next automatic update: "+ minutes_left + " minutes.";
        }

Visual Studio は、2 番目の関数の最終行に安全でないクロス スレッドとしてフラグを立てています。問題を解決するためにこれを書き直す方法を誰かが提案できますか?

乾杯

4

4 に答える 4

4

System.Windows.Forms.Timerの代わりに使用System.Timers.Timer

または、Timer のSynchronizingObjectプロパティを使用します。

SynchronizingObject が null の場合、Elapsed イベントを処理するメソッドがシステム スレッド プールのスレッドで呼び出されます。システム スレッド プールの詳細については、ThreadPool を参照してください。

Elapsed イベントがボタンなどの視覚的な Windows フォーム コンポーネントによって処理される場合、システム スレッド プールを介してコンポーネントにアクセスすると、例外が発生するか、機能しない可能性があります。SynchronizingObject を Windows フォーム コンポーネントに設定することで、この影響を回避します。これにより、Elapsed イベントを処理するメソッドが、コンポーネントが作成されたのと同じスレッドで呼び出されます。

于 2012-08-21T09:33:59.597 に答える
2

他の人が示唆しているように、を使用しますSystem.Windows.Forms.Timer。スレッドプールスレッドで動作する、とは異なりSystem.Threading.Timer、UIスレッドでtickイベントが呼び出されることが保証されます。

UIスレッドは、UIを変更できる唯一のスレッドです。これが、を書き込もうとして例外が発生する理由ですlbl_dyn_status.Text

于 2012-08-21T09:40:14.183 に答える
1

System.Timers.Timer の代わりに System.Windows.Forms.Timer タイマーを使用します。

于 2012-08-21T09:35:40.487 に答える
0

ハンドラを次のように変更します

public void IdleDisplay(object source, ElapsedEventArgs e)
{
    if (lbl_dyn_status.InvokeRequired)
    {
        this.Invoke(IdleDisplay)
    }
    else
    {
        if (minutes_left > 0)
        {
            minutes_left = minutes_left - 1;
        }

        lbl_dyn_status.Text = string.Format(
            "Time until next automatic update: {0} minutes.",
             minutes_left);
    }
}

この方法では、スレッドを自由に使用できますがSystem.Threading.Timer、ハンドラーでクロススレッド呼び出しをチェックします。検出された場合、呼び出しはFormクラスを介してメイン GUI スレッドで呼び出されます。

これについては、MSDN で詳しく説明されています。

より一般的には、このように時間をカウントするためにタイマーを使用しないでください。タイマーのスレッド バウンドが多いほど、実際の経過時間から逸脱する可能性が高くなります。タイマーを使用してクロックの更新をスケジュールできますが、反復カウンターを使用するのではなく、固定ポイントからの経過時間を計算する必要があります。

于 2012-08-21T09:42:27.193 に答える