2

私はイベントハンドラを持っています:

 private void Control_Scroll(object sender, ScrollEventArgs e)
 {
     UpdateAnnotations();
 }     

最後のスクロール イベントが 100 ミリ秒を経過してからアクションを実行するなど、ユーザーがスクロールを停止した場合にのみ注釈を更新したいと考えています。

それを行うための最も簡単で再利用可能な方法は何でしょうか。できればのような静的メソッドですpublic static void DelayedAction(Action action, TimeSpan delay)

.NET 4.0 を使用しています。

4

5 に答える 5

3

Rx (Reactive Extensions) の質問に対するこの回答を参照してください。( Observable.FromEventを使用して、イベントからオブザーバブルを作成できます。)

于 2013-02-28T12:21:40.530 に答える
2

フォーム上の複数のコントロールを同時に使用してこれを試しましたが、外部で再利用できます。

private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
    if (DelayedAction(100, sender))
        UpdateAnnotations();
}

Dictionary<object, Timer> timers = new Dictionary<object, Timer>();
bool DelayedAction(int delay, object o)
{
    if (timers.ContainsKey(o))
        return false;

    var timer = new Timer();
    timer.Interval = delay;
    timer.Tick += (s, e) =>
        {
            timer.Stop();
            timer.Dispose();
            lock(timers)
                timers.Remove(o);
        };

    lock(timers)
        timers.Add(o, timer);

    timer.Start();
    return true;
}

ユーザーが2つのコントロールを同時に押すことができない場合、別のコントロールが削除されると同時にタイマーが挿入される可能性があるため、辞書はロックされています。

于 2013-02-28T12:36:47.640 に答える
2

私はこのようなもので行きます

class MyClass
{
   private System.Timers.Timer _ScrollTimer;
   public MyClass()
   {
       _ScrollTimer= new System.Timers.Timer(100);
       _ScrollTimer.Elapsed += new ElapsedEventHandler(ScrollTimerElapsed);
   }

   private void ResetTimer()
   {
        _ScrollTimer.Stop();
        _ScrollTimer.Start();
   }

   private void Control_Scroll(object sender, ScrollEventArgs e, TimeSpan delay)
    {
        ResetTimer();
    }    

    private void ScrollTimerElapsed(object sender, ElapsedEventArgs e)
    {
        _ScrollTimer.Stop();
        UpdateAnnotations();           
    }
}

ユーザーがスクロールするたびにタイマーがリセットされ、スクロールが 100 ミリ秒停止したときにのみ TimerElapsed が発生し、注釈を更新できます。

于 2013-02-28T12:22:13.430 に答える
1

イベントが発生した時刻 (DateTime.Now) を保存できず、呼び出されたときに前回からの経過時間を確認できますか (たとえば、DateTime.Now - lastExecutionTime > minTime)。

** アップデート **

または、静的ヘルパーのアイデアに基づくより一般的な方法:

public static void DelayedAction(Action action, TimeSpan delay)
{
    var delayedActionTimer = new Timer(x => action(), null, delay, TimeSpan.FromMilliseconds(-1));
}

明らかに作業が必要です...たとえば、タイマーをフィールドに保存し、ユーザーがスクロールするたびに遅延をリセット(変更)できます

于 2013-02-28T12:17:43.193 に答える
1

このクラスを試してください:

public class ActionHelper
{
    private static Dictionary<Delegate, System.Threading.Timer> timers =
        new Dictionary<Delegate, System.Threading.Timer>();

    private static object lockObject = new object();

    public static void DelayAction(Action action, TimeSpan delay)
    {
        lock (lockObject)
        {
            System.Threading.Timer timer;
            if (!timers.TryGetValue(action, out timer))
            {
                timer = new System.Threading.Timer(EventTimerCallback, action,
                    System.Threading.Timeout.Infinite,
                    System.Threading.Timeout.Infinite);
                timers.Add(action, timer);
            }
            timer.Change(delay, TimeSpan.FromMilliseconds(-1));
        }
    }

    public static void EventTimerCallback(object state)
    {
        var action = (Action)state;
        lock (lockObject)
        {
            var timer = timers[action];
            timers.Remove(action);
            timer.Dispose();
        }
        action();
    }
}

特徴:

  • ヘッドセーフ
  • 複数の同時アクションをサポート

使用法:

private void Control_Scroll(object sender, ScrollEventArgs e)
{
    ActionHelper.DelayAction(UpdateAnnotations, TimeSpan.FromSeconds(1));
}

メソッドは別のスレッドで呼び出されることに注意してください。UI 作業を行う必要がある場合は、Control.Invoke(WinForms) またはDispatcher.Invoke(WPF)を使用する必要があります。

// The method is contained in a Form (winforms)
private void UpdateAnnotations()
{
    if (this.InvokeRequired)
        this.Invoke(new Action(UpdateAnnotations));
    else
    {
        MessageBox.Show("Method is called");
    }
}
于 2013-02-28T13:23:18.327 に答える