2010-09-27 3 views
2

Мне нужно удалить элементы из списка через несколько секунд после добавления. У меня есть ObservableCollection, к которому я добавляю некоторые сообщения. Мне нужно, чтобы их удаляли, скажем, через 5 секунд после их добавления. Я пытался создать функцию, ответственную за добавление элементов и установки таймера:Как удалить элементы из списка через x секунд после их добавления

public void AddInfoItem(string info) 
    { 
     infoList.Add(info); 
     Timer newTimer = new Timer(5000); 
     newTimer.Elapsed += new ElapsedEventHandler(this.TimerFunction); 
     newTimer.Enabled = true; 
     newTimer.Start(); 
    } 
public void TimerFunction(Object sender, EventArgs e) 
    { 
     infoList.Clear(); 
    } 

Я даже не посылать никаких параметров, какой элемент должен быть удален причиной вторая функция вызывает исключение. Может ли кто-нибудь описать правильное решение для добавления элемента и его удаления через некоторое время?

Sory для того, чтобы не писать его раньше. Исключение составляет

этот тип CollectionView не поддерживает изменения в его sourcecollection из нити, отличающиеся от dispatecher нити

+2

Какое исключение? – Val

+0

Как сказал Вал - какое исключение? –

ответ

1

Если в WPF используется DispatcherTimer. Я обычно использую что-то вроде этого:

public static void Delay(int milliseconds, Action action) 
{ 
    var t = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(milliseconds) }; 
    t.Tick += (o, e) => { t.Stop(); action.Invoke(); }; 
    t.Start(); 
} 

DispatcherTimer удостоверится событие вызывается в том же потоке, чтобы не столкнуться с проблемами многопоточности. Другой альтернативой является создание коллекции, которую вы привязываете к потоковому безопасному. Но на самом деле, зная, какое исключение вы получили вместо угадывания, было бы проще.

Кроме того, если вы быстро добавляете и удаляете множество предметов или требуете, чтобы ваше время было точным, вам нужно было подумать о чем-то другом; DispatcherTimer не очень точен и имеет некоторые накладные расходы, поэтому многие экземпляры его будут потреблять некоторые ресурсы.

-2

убедитесь, что ваш сборщик мусора не выбрасывайте Infolist. Попробуйте GC.KeepAlive (infoList)

+1

Кажется маловероятным, чтобы быть причиной ... Поскольку infoList определен (и, таким образом, ссылка) где-то вне метода, кажется маловероятным, что GC станет причиной.Вам нужно будет установить 'infoList = null' для GC, чтобы очистить его, и это даст« NullReferenceException »(который, надеюсь, не понадобится решить вопрос SO ...). –

+0

GC.KeepAlive ничего не делает. Вы можете реализовать его так: 'void Foo (панель объектов) {}'. Это всегда полезно, когда у вас нет ссылок на объект, который используется где-то вне досягаемости сборщика мусора, например неуправляемый код. –

0

Звучит как работа для Reactive Extensions. Вот a link до 101 Rx Образцы, чтобы показать вам, как идти.

В основном то, что вы хотите, чтобы сделать (частично псевдокод)

Observable 
.FromEvent<NotifyCollectionChangedEventArgs>(infoList, "CollectionChanged") 
.Where(args => args.Action == NotifyCollectionChangedAction.Add) 
.Delay(TimeSpan.FromSeconds(5)) 
.ObserveOnDispatcher() 
.Subscribe(args => infoList.Remove(args.NewItems)); 

Нет необходимости иметь дело с таймерами и без каких-либо утечек до тех пор, как вы распоряжаться IDisposable, возвращаемый методом Subscribe, когда вы сделайте с ним.

Edit: Shameless самостоятельно плагин - Я сделал blog post с рабочим примером консольного приложения. Единственное, что у вас есть, это то, что вы захотите сохранить вызов ObserverOnDispatcher() в своем приложении WPF, или вы получите некоторые ошибки потоковой передачи.

+0

Хотя это отлично работает, когда вы уже активно используете реактивные расширения в приложении, это похоже на излишнюю проблему для одной простой проблемы? – ForbesLindesay

+0

@ Tuskan360 Как только вы начнете использовать Rx, вы увидите множество мест, где вы можете написать гораздо более простой код, чем тот, который у вас уже есть. Как говорится, первый хит свободен. –

0

свайный на ответ Брайана выше, вот как вы это делаете с помощью ReactiveXaml «s ReactiveCollection, расширения ObservableCollection:

theCollection.ItemsAdded 
    .Delay(TimeSpan.FromSeconds(5)) 
    .Subscribe(theCollection.Remove); 
+0

Это похоже на действительно классную библиотеку! Я определенно добавляю его в свой список проектов, чтобы следить. –

1

Вместо удаление элементов из списка по таймеру, то почему бы не хранить время истечения срока действия с каждый элемент, когда он добавлен, и игнорировать или удалять истекшие элементы только тогда, когда вам нужно получить элемент или перебрать список?