Как удалить элементы из списка х секунд после их добавления

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

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();
    }

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

Извините, что не написал это раньше. Исключение составляет

этот тип коллекционного представления не поддерживает изменения в его исходной коллекции из потока, отличного от потока диспетчера

5 ответов

Решение

Если вы работаете в 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 не очень точен и несет некоторые накладные расходы, поэтому многие его экземпляры будут потреблять некоторые ресурсы.

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

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

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

Похоже, работа для реактивных расширений. Вот ссылка на 101 Rx Samples, чтобы показать вам, как начать работу.

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

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

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

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

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

Другие вопросы по тегам