【问题标题】:Update WPF UIElements using Parallel.Foreach or Threads使用 Parallel.Foreach 或 Threads 更新 WPF UIElements
【发布时间】:2015-10-24 04:44:49
【问题描述】:

我在使用 Parallel.Foreach 或 IEnumerable.AsParallel().ForAll() 或 Threads 更新 Canvas 的内容时遇到了一些问题。

我在 Canvas 中有很多线条,当用户调整窗口大小时,我需要将它们的坐标相对于它们所在的 Canvas 的新大小进行更改。

我把我的线放进去

    IEnumerable<Line> lineCollection = canvas.Children.OfType<Line>();

然后我尝试使用 Parallel.Foreach 或 IEnumerable.AsParallel().ForAll() 将它们并行循环

在这种情况下,我会收到 AggregateException。它说,调用线程不能访问这个对象,因为主线程拥有它。

如何使用我的 UIElements 做到这一点。

这是我的代码:

    private void canvas_SizeChanged(object sender, SizeChangedEventArgs e)
    {

        Double hDelta = e.NewSize.Height / e.PreviousSize.Height;

        if (Double.IsInfinity(hDelta)) return;

        IEnumerable<Line> LineCollection = canvas.Children.OfType<Line>();
        try
        {
            Parallel.ForEach(LineCollection, (line) =>
            {
                Double topProp = (Double)line.GetValue(Canvas.TopProperty) * hDelta;

                line.SetValue(Canvas.TopProperty, topProp);
            });
        }
        catch (AggregateException ae)
        {
            ae.Handle((x) =>
            {
                if (x is Exception)
                {
                    MessageBox.Show(x.ToString(), "error");
                }
                return false;
            });
        }
    }

我在这一行收到一个错误:

line.SetValue(Canvas.TopProperty, topProp);

【问题讨论】:

  • 你不能。只有主线程可以访问 UI 对象。
  • 也许这会回答你的问题并给你一个解决方案:stackoverflow.com/questions/9980053/…
  • 你实际画了多少线?你的方法似乎有点矫枉过正。
  • 几千行。我必须使用什么方法?

标签: c# wpf multithreading canvas parallel.foreach


【解决方案1】:

这解决了我的问题。

        Line[] keysLineCollection = YAxisKeys.Children.OfType<Line>().ToArray();
        Label[] keysLabelCollection = YAxisKeys.Children.OfType<Label>().ToArray();
        try
        {
            new Thread(delegate ()
            {
                Parallel.ForEach(keysLineCollection, (line, loopstate, elementIndex) =>
                {

                    /*keysLineCollection[elementIndex]*/
                    line.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        Double topProp = ((Double)line.GetValue(Canvas.TopProperty) - 11.0) * hDelta + 11.0;
                        switch (topProp - 11.0 < 0)
                        {
                            case true:
                                line.Visibility = Visibility.Hidden;
                                break;
                            default:
                                line.Visibility = Visibility.Visible;
                                break;
                        }
                        line.SetValue(Canvas.TopProperty, topProp);
                    }));
                    keysLineCollection[elementIndex] = line;
                });
            }).Start();

            new Thread(delegate ()
            {
                Parallel.ForEach(keysLabelCollection, (label, loopstate, elementIndex) =>
                {

                    /*keysLabelCollection[elementIndex]*/
                    label.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        Double topProp = (Double)label.GetValue(Canvas.TopProperty) * hDelta;
                        switch (topProp < 0)
                        {
                            case true:
                                label.Visibility = Visibility.Hidden;
                                break;
                            default:
                                label.Visibility = Visibility.Visible;
                                break;
                        }
                        label.SetValue(Canvas.TopProperty, topProp);
                    }));
                    keysLabelCollection[elementIndex] = label;
                });
            }).Start();
        }
        catch (AggregateException ae)
        {
            ae.Handle((x) =>
            {
                if (x is Exception)
                {
                    MessageBox.Show(x.ToString(), "error");
                }
                return false;
            });
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.ToString(), "error");
        }

我用过

Line[] keysLineCollection = YAxisKeys.Children.OfType<Line>().ToArray();

而不是

IEnumerable<Line> lineCollection = canvas.Children.OfType<Line>();

并将 Dispatcher 应用于数组中的元素。

它对我很有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-23
    • 2016-10-05
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多