2016-04-04 14 views
1

私はUserControlのイベントに登録していますが、このイベントはスクロールバーを移動するたびにスローされます(つまり、多くのイベントを受け取ります)。残念ながら、ユーザーがスクロールバー(== MouseUp)の使用を終了したときに通知するイベントはありません。コードの実行を遅らせます

私たちは300ミリ秒以来スクロールバーから新しい通知を受け取らなかった場合にのみモデルを更新する仕組みを実装することに決めました。

私は、Timerでこれを行い、ScrollBarイベントが来るたびにタイマーをリセットする方法を見ることができます。

私はLinqとDelayでそれを行う方法があるのだろうかと思っていましたか?

private Action _actionOnMoved; 

private void OnScrollBarMoved(object sender, EventArgs args){ 

} 

EDIT

私は潜在的に重複して答えを読んだが、スロットリングは私が求めているものをと同じものではありません。私の場合、指定された時間よりもイベントが来るまでは、この変更を適用するには3〜5秒かかりますので、何もしたくない(最初のものでもない)。与えられたリンクで

  • を、最初の呼び出しは関係なく、私の場合は何
  • 実行されない呼び出しが遅延以内に行われた場合、コールはまだ後に実行する必要があります。異なる点についてだから、

たとえば、このイベントが100ミリ秒ごとにトリガーされ、遅延が300ミリ秒である場合、私は自分のメソッドを呼び出さないことを期待しています。

+3

お使いのプラットフォームは何ですか? winforms、wpfまたはASP – Kira

+0

Winformですが、サードパーティのライブラリからイベントを受け取ったとします。より具体的なイベントに登録する方法よりも、問題の遅れにもっと関心があります。 – J4N

+0

これは同様の方法で解決できますが、ここで質問されているものとは異なるスロットル問題を扱うので、私はとにかく質問を再開します。 – Larry

答えて

1

あなたは

object _lock = new object(); 

SomeEvent += (s, e) => 
{ 
    lock(_lock) 
    { 
     Monitor.PulseAll(_lock); // pulse any (if any) awaiting events 
     if(!Monitor.Wait(_lock, 5000)) // delay 
     { 
      ... // call event handler 
       // we are here if timeout is expired 
     } 
    } 
} 

未テストの次にイベントハンドラをラップすることができますが、ここでの考え方は次のとおりです。イベントはあなたがパルスまたはタイムアウトのいずれかを待って起動する受信されたとき。パルスが来たら(別のイベントが受信されたことを意味する)、そのまま終了します。タイムアウトが発生すると(別のイベントが発生しないことを意味します)、イベントハンドラを呼び出します。

注:非同期ではないため、イベント発信者(コールまたはSomeEvent)は遅延のためにブロックされます。

SomeEvent += (s, e) => Task.Run(() => 
{ 
    ... // the rest of code 
} 

しかし、あなたはあなたが必要とするスレッドに(呼び出し)派遣する必要がありますので、それは、他のいくつかのスレッドでイベントハンドラを上昇するだろう:あなたは Task.Runlockをラップする必要があるかもしれません。

+0

すべてのイベントは、待機する時間を「リセット」する必要があります。待つ時間の終わりに、私はちょうど1つのイベント – J4N

+0

@ J4Nを持つ必要があります、それはまさに起こっていることです。もっと説明が必要ですか?何が分かりませんか?待機イベントはどのように破棄されるのですか?タイムアウトが満了する前にパルスがあり、 'if'がfalseであるので、イベントハンドラは呼び出されないので、これは破棄されます。 – Sinatr

+0

私はそれを正しく読まなかった、私はこれがうまくいくはずだと思う。私は非同期の方法を使用し、それをテストするが、これは良いと思われる – J4N

0

whileループとThreadPoolを使用してイベントを監視します。

​​
+0

最初のmouseWheelはロックされていません。第二に、私はポーリングを行う大きなファンではなく、実際には悪いアイデア(CPU使用率)のように見えます。 – J4N

0

私はSinatrの解答の修正版を使用して終了しました:

public static EventHandler CreateDelayedEventHandler(EventHandler<EventArgs> handler, TimeSpan delay) 
{ 
    object lockObject = new object(); 

    return (s, e) => 
    { 
     Task.Run(() => 
     { 
      lock (lockObject) 
      { 
       Monitor.PulseAll(lockObject); 
       if (!Monitor.Wait(lockObject, delay)) 
       { 
        handler(s, e); 
       } 
      } 
     }); 
    }; 
} 

私は今てきた唯一の疑問は、単に潜在的に何もしないように作成されますどのように多くの作業です。

+0

* "何も起こらないように何個のタスクを作成するか" * - 各イベントごとに1つのタスクしか待ちません。 'lock'(または起動しないこと)の前に多くのタスクを作成して待機させることは可能ですが、最後に作成されたタスクはawating(btw、' PulseAll'は不要です。 'Pulse'は十分です単一のタスクだけが 'Wait'に到達できることを保証し、単一のタスクだけがロックを獲得することを保証します)。私はこれについて心配しません。必要に応じて、特定のイベントの動作を測定して、イベントが多すぎるかどうかを確認し、許可するタスクの最大数を制限することができます。 – Sinatr

+0

@Sinatrはい、それはコストがかかりますか?タスクを作成する意味は?スレッドを作成するのは高価だったことは分かっていますが、タスクについてはわかりません。私は 'PulseAll'のために見ました。私の場合は、1秒で200個のイベントが突然発生する可能性があるので、200個の新しいタスクがどれくらいのリソースを使用するのかはわかりません。 – J4N

+0

[http://stackoverflow.com/a/19348243/1997232]を参照してください。 – Sinatr

関連する問題