2009-03-27 15 views
2

タイムアウト後にObservableCollection<Notification>からNotificationを削除します。追加されたアイテムごとに新しいThreadPoolスレッドを開始してそこにThread.Sleepを入れるよりも良い方法はありますか? Nidonocuの回答に基づいてタイムアウト後にコレクションからアイテムを削除する


決勝コード:

public class NotificationCollection : ObservableCollection<Notification> 
{ 
    private readonly DispatcherTimer timer; 

    public NotificationCollection() 
     : this(Application.Current.Dispatcher) 
    { 
    } 

    public NotificationCollection(Dispatcher dispatcher) 
    { 
     this.timer = 
      new DispatcherTimer(DispatcherPriority.DataBind, dispatcher); 
     this.timer.Tick += this.TimerOnTick; 
    } 

    protected override void InsertItem(int index, Notification item) 
    { 
     base.InsertItem(index, item); 
     if (!this.timer.IsEnabled) 
     { 
      this.StartTimer(item); 
     } 
    } 

    private void StartTimer(Notification item) 
    { 
     var timeout = item.Timestamp + item.Timeout - DateTime.UtcNow; 
     if (timeout < TimeSpan.Zero) 
     { 
      timeout = TimeSpan.Zero; 
     } 

     this.timer.Interval = timeout; 
     this.timer.Start(); 
    } 

    private void TimerOnTick(object sender, EventArgs e) 
    { 
     this.timer.Stop(); 

     this.RemoveAt(0); 
     if (this.Count > 0) 
     { 
      this.StartTimer(this[0]); 
     } 
    } 

答えて

2

は、タイマーのいくつかの種類がより適切ではないでしょうか?その後、次の通知が削除されるまでの時間がある場合、残りのアイテムが残っていればタイマーを再開し、もう一度もう一度チェックするスレッドを1つだけ持つことができます。


編集:あなたは、.NET 3.5であるので 私はDispatcherTimerを使用するWPFを想定しています。これは、自動的に正しいスレッドを使用して、私が理解している通りにそれを渡すメソッドを実行します。試してみると、未テストのコードです:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Collections.ObjectModel; 
using System.Windows.Threading; 
using System.Windows; 

namespace WpfApplication1 
{ 
    public class Notification 
    { 
     public DateTime TimeStamp { get; set; } 
    } 

    public class NotificationCollection : ObservableCollection<Notification> 
    { 
     private readonly TimeSpan timeout; 

     private DispatcherTimer timer; 

     public NotificationCollection(TimeSpan timeout) 
      : this(timeout, Application.Current.Dispatcher) { } 

     public NotificationCollection(TimeSpan timeout, Dispatcher dispatch) 
     { 
      this.timeout = timeout; 
      timer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Normal, this.Cleanup, dispatch); 
     } 

     protected override void InsertItem(int index, Notification item) 
     { 
      base.InsertItem(index, item); 
      timer.Start(); 
     } 

     private void Cleanup(object o, EventArgs e) 
     { 
      timer.Stop(); 
      // Sanity 
      if (this.Count == 0) 
       return; 

      var deadList = from note in this.Items 
          where note.TimeStamp + this.timeout - DateTime.UtcNow < TimeSpan.Zero 
          select note; 
      foreach (var note in deadList) 
      { 
       this.Remove(note); 
      } 

      if (this.Count > 0) 
       timer.Start(); 
     } 
    } 
} 
+0

例を挙げてください。 1つのスレッドのみを使用しているすべての試みは失敗しました。主に、スレッドがメインスレッドで削除されなければならないことが原因です。 – dtb

+0

作業中... – Nidonocu

+0

ありがとうございます。私はそれを少し修正し、結果を質問エリアに掲載しました。 – dtb

0

私は挿入されたオブジェクトごとにスレッドを作成しません。代わりに、私は単一のクリーンアップスレッドを持つか、タイマーオブジェクトを使用します。スレッドが起動すると、古い項目をクリーンアップするリストを歩くことができます。

また、インデックス演算子やその他のアクセサメソッドをオーバーライドして、クリーンアップする必要がありますがまだ完了していないアイテムを許可しません。