“调用线程无法访问此对象,因为不同的线程拥有它”从WPF中的不同线程更新UI控件时出错

时间:2017-01-28 21:41:41

标签: c# wpf multithreading invoke dispatcher

我有从主线程调用的方法。此方法正在创建一个新线程。代码如下所示:

MouseCursorWallObject MouseCursorWall = null;
List<MovingRectangle> MovingRectangles = null;

DrawingImage RenderedImage;


public MainWindow()
    {
        InitializeComponent();
        PrepareObjects();            
        GameLoopRun();                       
    }

private void GameLoopRun()
    {
        Thread thread = new Thread(() =>
        {
            while (true)
            {
                DateTime dtStart = DateTime.Now;

                Events();
                Update();
                Display();

                DateTime dtEnd = DateTime.Now;
                TimeSpan ts = dtEnd - dtStart;
                if (SkipTicks - ts.TotalMilliseconds >= 0)
                {
                    Thread.Sleep((int)(SkipTicks - ts.TotalMilliseconds));
                }
            }
        });
        thread.Start();
    }

在Display()方法中,我尝试更新图像控制。 “Display()”方法如下所示:

private void Display()
    {
        DrawingGroup imageDrawings = new DrawingGroup();

        // Drawing main canvas
        imageDrawings.Children.Add(DrawingObject(500, 350, 0, 0, new Uri(@"Images\gameCanvas.jpg", UriKind.Relative)));

        // Drawing mouse cursor wall
        imageDrawings.Children.Add(DrawingObject(MouseCursorWall.Width, MouseCursorWall.Height, MouseCursorWall.GetLocX, MouseCursorWall.GetLocY, MouseCursorWall.DisplayTexture));

        for (int i = 0; i < MovingRectangles.Count; i++)
        {
            MovingRectangle o = MovingRectangles[i];

            // Drawing moving object
            imageDrawings.Children.Add(DrawingObject(20, 20, o.GetLocX, o.GetLocY, o.TextureUri));
        }

        if (GamePause == true)
        {

        }
        RenderedImage = new DrawingImage(imageDrawings);

        // Image control on main UI thread
        renderImage.Dispatcher.Invoke(() =>
        {
            renderImage.Source = RenderedImage;
        });
    }

问题是当我尝试使用Dispatcher.Invoke更新图像控制时我收到错误“调用线程无法访问此对象,因为另一个线程拥有它”。我尝试了很多不同的选择,只有一个可以正常工作:

private void Display()
    {
        this.Dispatcher.Invoke(() => {
            DrawingGroup imageDrawings = new DrawingGroup();

            // Drawing main canvas
            imageDrawings.Children.Add(DrawingObject(500, 350, 0, 0, new Uri(@"Images\gameCanvas.jpg", UriKind.Relative)));

            // Drawing mouse cursor wall
            imageDrawings.Children.Add(DrawingObject(MouseCursorWall.Width, MouseCursorWall.Height, MouseCursorWall.GetLocX, MouseCursorWall.GetLocY, MouseCursorWall.DisplayTexture));

            for (int i = 0; i < MovingRectangles.Count; i++)
            {
                MovingRectangle o = MovingRectangles[i];

                // Drawing moving object
                imageDrawings.Children.Add(DrawingObject(20, 20, o.GetLocX, o.GetLocY, o.TextureUri));
            }

            if (GamePause == true)
            {

            }

            RenderedImage = new DrawingImage(imageDrawings);
            renderImage.Source = RenderedImage;
        });

    }

你能解释一下为什么“Display()”方法的第二个选项工作正常,但是第一个抛出异常?我做错了什么?

1 个答案:

答案 0 :(得分:3)

DrawingImageDrawingGroup都继承自DispatcherObject,这意味着需要从创建它们的线程访问它们。这就是为什么您的所有工作被调用回调度程序的版本正常工作。

正如Brian Reichle所指出的,这些对象也继承自System.Windows.Freezable,您可以利用它来允许跨线程访问对象。