2

私がしたいこと。SomeMethod が定期的に呼び出されるようにしたい。したがって、バックグラウンド スレッド メソッドの本体が渡された後、バックグラウンド スレッドからタイマーが開始されるようにしたいと考えています。_timer.Start()呼び出されましたが、TickHandler は呼び出されません。

コード:

using Timer = System.Windows.Forms.Timer;

class TestTimer
    {
        private Timer _timer;
        private Thread _thread;

        public TestTimer()
        {
            // create and initializing timer. but not started!
            _timer = new Timer();
            _timer.Tick += TickHandler;
            _timer.Interval = 60000; // 1 minute

            // create and start new thread
            _thread = new Thread(SomeMethod);
            _thread.Start();
        }

        private void TickHandler(object sender, EventArgs e)
        {
            // stop timer
            _timer.stop();

            //some handling

            // run background thread again
            _thread = new Thread(SomeMethod);
            _thread.Start();
        }   

        private void SomeMethod()
        {
            // some operations

            // start timer!
            TimerStart();
        }

        private void TimerStart()
        {
            _timer.Start();
        } 
    }

このようにデリゲートを追加すると、サルの方法で見つけました

internal delegate void TimerDelegate();

そして文字列を置き換えます

TimerStart(); 

Application.Current.Dispatcher.Invoke(new TimerDelegate(TimerStart), null);

すべて正常に動作します。誰かがトリックとは何かを説明できますか?

4

2 に答える 2

4

あなたは物事が少し混ざっています。

バックグラウンド スレッドで起動するタイマーが必要な場合は、それを開始するためのスレッドを作成する必要はありません (どのスレッドがメソッドを呼び出すかは関係ありません)。を使用するだけで、各イベントはスレッドプールスレッドで発生します。StartSystem.Timers.TimerElapsed

UI スレッドで起動するタイマーが必要な場合は、WPF を使用しているように見えるため、これまで使用していた Windows フォーム タイマーではなく、 を使用する必要があります。特定の UI スレッドでタイマーを作成(つまり を呼び出す) すると、すべてのイベントがそのスレッドで発生します。繰り返しますが、どのスレッドから呼び出すかは問題ではありません。System.Windows.Threading.DispatcherTimernewTickStart

コードで何が起こっているかの説明は次のとおりです。 非 UI スレッドで Windows フォーム タイマーを開始しています。この種のタイマーでは、メッセージを受信できるように、そのスレッドでメッセージ ポンプを実行する必要があります。非 UI スレッドであるため、メッセージ ポンプはありません。このメソッドを使用するDispatcher.Invokeと、タイマーの作成がアプリケーションのメイン UI スレッドにマーシャリングされ、機能するようになりました。しかし、それはすべて非常に冗長です。コードをそのままにしておく場合は、タイマーを に置き換えるだけでDispatcherTimer、呼び出しを削除できInvokeます。

または、.NET 4.5 を使用している場合は、await/async を使用してこれをすべて簡単にすることができます (必ずSomeMethodUI スレッドから呼び出してください)。

async Task SomeMethod(CancellationToken ct)
{
    while (!ct.IsCancellationRequested)
    {
        await Task.Run(() => DoAsyncStuff(), ct);

        DoUIStuff();

        await Task.Delay(TimeSpan.FromMinutes(1), ct);
    }
}
于 2013-10-01T06:24:23.333 に答える
0

MSDNで説明できます。

注: Windows フォーム タイマー コンポーネントはシングル スレッドであり、55 ミリ秒の精度に制限されています。精度の高いマルチスレッド タイマーが必要な場合は、System.Timers 名前空間の Timer クラスを使用します。

于 2013-10-01T06:27:58.380 に答える