【问题标题】:Error when adding items to listbox on many threads在多个线程上将项目添加到列表框时出错
【发布时间】:2017-02-05 18:53:32
【问题描述】:

我有一个 WPF 应用程序,我想在许多线程上将项目添加到列表框。 当我做这样的事情时

        listBox.Items.Clear();
        var lastgames = db.GameResults.OrderByDescending(c => c.DataGry).ToList();
        Parallel.ForEach(lastgames, game =>
        {
            listBox.Items.Add(game.score);
        });

显然会抛出异常

调用线程无法访问此对象,因为另一个线程拥有它。

我听说过 WPF 中的后台工作人员,但我不知道如何使用它。

【问题讨论】:

  • 要处理长操作或导致 UI 被锁定的操作,您需要使用 ThreadPoolDispatcher.Invoke。示例:stackoverflow.com/questions/36521365/…
  • @S.Akbari ive 使用了您的代码并将 parallel.foreach 替换为正常的 foreach 是我应该做的吗?

标签: c# wpf multithreading listbox


【解决方案1】:

由于 UI 元素只能从最初创建它们的线程(即 UI 线程)访问,因此使用 Parallel.ForEach 将项目添加到 ListBox 是没有意义的。

你应该使用一个简单的 foreach 循环:

listBox.Items.Clear();
var lastgames = db.GameResults.OrderByDescending(c => c.DataGry).ToList();
foreach(var game in lastgames)
    listBox.Items.Add(game.score);

另一种选择是将项目添加到线程安全集合中,然后在填充后将 ListBox 的 ItemsSource 属性设置为该集合:

 object _lock = new _lock();
 List<int> scores = new List<int>();
 listBox.Items.Clear();
 var lastgames = db.GameResults.OrderByDescending(c => c.DataGry).ToList();
 Parallel.ForEach(lastgames, game =>
 {
     lock (_lock)
         scores.Add(game.score);
 });
 listBox.ItemsSource = scores;

这有点毫无意义,因为您仍然需要在循环的每次迭代中同步对集合的访问。所以你最好使用一个简单的 foreach 循环并在同一个线程上添加所有项目。

【讨论】:

  • 阻止收藏是我想要的。谢谢大佬的解释。
【解决方案2】:

您不能使用来自 UI 线程以外的其他线程的 UI 控件。您应该改用调度程序。

例如:

 Application.Current.Dispatcher.BeginInvoke(
  DispatcherPriority.Background,
  new Action(() => {
      listBox.Items.Add(game.score);
 }));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多