WPF Dispatcher.BeginInvoke和线程访问

时间:2013-05-20 19:48:35

标签: c# wpf dispatcher

我很难理解为什么这个简单的方法不起作用 如果我理解正确,UIElements只能由他们自己的线程更改,后台线程不能。 尝试此代码时。它抛出:

  

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

参考代码:

        Canvas c = new Canvas();
        RootWindow.AddChild(c);

        Thread r = new Thread( new ThreadStart(() =>
        {
            Polygon p = new Polygon();
            PointCollection pC = new PointCollection();
            pC.Add(new Point(1.5, 4.5));
            pC.Add(new Point(-7, 9));
            pC.Add(new Point(1.5, -5));
            pC.Add(new Point(10, 9));
            p.Points = pC;
            p.Stroke = Brushes.Black;
            p.Fill   = Brushes.Green;

            c.Dispatcher.BeginInvoke( DispatcherPriority.Normal , new Action( () => { c.Children.Add(p); } ));

        }));
        r.SetApartmentState(ApartmentState.STA);
        r.Start();

1 个答案:

答案 0 :(得分:1)

Polygon 是一个UIElement。因此,只能从创建它的线程访问它。您在后台线程上创建了它,因此只能从该线程访问它。当你试图从UI线程访问它时,它会对你大喊大叫。

您需要在UI线程中创建对象,对其进行修改并将其添加到容器中。您刚刚显示的代码都不属于后台线程。

也许,如果你需要做一些复杂的事情来生成Point个对象的序列,而不是仅使用4个硬编码值,那么这将是可能所属的唯一部分在后台线程中。如果您需要查询数据库,或者执行一些昂贵的图形操作来确定点应该是什么,并且需要足够长的时间才能在UI线程中执行它,那么请创建一个生成{{1}的任务在另一个线程中,然后让UI线程获取这些点,将它们放入List<Point>并将其添加到窗口。