【问题标题】:How to remove items from list x seconds after adding them添加项目后如何从列表中删除项目 x 秒
【发布时间】:2010-09-28 11:33:02
【问题描述】:

我需要在添加项目几秒钟后从列表中删除它们。我现在有一个 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();
    }

我什至没有发送任何参数应该删除哪个项目,因为第二个函数引发了异常。有人可以描述一个适当的解决方案来添加项目并在一段时间后将其删除吗?

抱歉没有早点写。例外是

这种类型的collectionview不支持从与dispatcher线程不同的线程更改其sourcecollection

【问题讨论】:

  • 正如 Val 所说 - 有什么例外?

标签: wpf timer observablecollection


【解决方案1】:

与其在计时器上从列表中删除项目,为什么不在每个项目添加时存储过期时间,并且仅在需要检索项目或迭代列表时才忽略或删除过期项目?

【讨论】:

    【解决方案2】:

    如果在 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 不是很精确,确实会带来一些开销,所以它的很多实例会消耗一些资源。

    【讨论】:

      【解决方案3】:

      听起来像是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));
      

      只要处理完 Subscribe 方法返回的 IDisposable,就不需要处理计时器,也不会泄漏。

      编辑: 无耻的自我插件 - 我用一个工作控制台应用程序示例做了一个blog post。您将拥有的一个区别是您需要在 WPF 应用程序中保留 ObserverOnDispatcher() 调用,否则您会遇到一些线程错误。

      【讨论】:

      • 虽然当您已经在应用程序中大量使用响应式扩展时,这确实很有效,但对于一个简单的问题来说似乎有点矫枉过正?
      • @Tuskan360 一旦你开始使用 Rx,你会看到很多地方你可以编写比你已有的更简单的代码。正如他们所说,第一次点击是免费的。
      【解决方案4】:

      根据上面 Bryan 的回答,您可以通过 ReactiveXaml 的 ReactiveCollection(ObservableCollection 的扩展)来做到这一点:

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

      【讨论】:

      • 看起来很酷的库!我肯定会将它添加到我要关注的项目列表中。
      【解决方案5】:

      确保您的垃圾收集器没有丢弃您的 infoList。试试 GC.KeepAlive(infoList)

      【讨论】:

      • 似乎不太可能是原因...由于 infoList 在方法之外的某个地方定义(并因此被引用),G​​C 似乎不太可能成为原因。您必须为 GC 设置 infoList = null 来清理它,这会给出一个 NullReferenceException (希望不需要一个 SO 问题来解决......)。
      • GC.KeepAlive 什么都不做。你可以像void Foo(object bar){} 那样实现它。仅当您没有对在垃圾收集器范围之外使用的对象(例如非托管代码)没有任何引用时,它才有用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-12
      相关资源
      最近更新 更多