对 WPF 控件的线程安全调用 [英] Thread-safe calls to WPF controls

查看:63
本文介绍了对 WPF 控件的线程安全调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 WPF 和 C# 编写我的第一个程序.我的窗口只包含一个简单的画布控件:

I am just writing my first program using WPF and C#. My windows just contains a simple canvas control:

<StackPanel Height="311" HorizontalAlignment="Left" Name="PitchPanel" VerticalAlignment="Top" Width="503" Background="Black" x:FieldModifier="public"></StackPanel>

这很好用,我可以从 Window.Loaded 事件访问这个名为 PitchPanel 的画布.

This works fine and from the Window.Loaded event I can access this Canvas called PitchPanel.

现在我添加了一个名为 Game 的类,它的初始化方式如下:

Now I have added a class called Game which is initialized like this:

public Game(System.Windows.Window Window, System.Windows.Controls.Canvas Canvas)
{
    this.Window = Window;
    this.Canvas = Canvas;
    this.GraphicsThread = new System.Threading.Thread(Draw);
    this.GraphicsThread.SetApartmentState(System.Threading.ApartmentState.STA);
    this.GraphicsThread.Priority = System.Threading.ThreadPriority.Highest;
    this.GraphicsThread.Start();
    //...
}

如您所见,有一个名为 GraphicsThread 的线程.这应该以尽可能高的速率重绘当前游戏状态,如下所示:

As you can see, there is a thread called GraphicsThread. This should redraw the current game state at the highest possible rate like this:

private void Draw() //and calculate
{
   //... (Calculation of player positions occurs here)
   for (int i = 0; i < Players.Count; i++)
   {
       System.Windows.Shapes.Ellipse PlayerEllipse = new System.Windows.Shapes.Ellipse();
       //... (Modifying the ellipse)
       Window.Dispatcher.Invoke(new Action(
       delegate()
       {
           this.Canvas.Children.Add(PlayerEllipse);
       }));
    }
}

但是虽然我使用了一个由主窗口调用的调度程序,它在创建游戏实例时传递,但发生了一个未处理的异常:[System.Reflection.TargetInvocationException],内部异常表示我无法访问该对象,因为它由另一个线程(主线程)拥有.

But although I have used a dispatcher which is invoked by the main window which is passed at the creation of the game instance, an unhandled exception occurs: [System.Reflection.TargetInvocationException], the inner exceptions says that I cannot access the object as it is owned by another thread (the main thread).

游戏在应用程序的 Window_Loaded 事件中初始化:

The Game is initialized in the Window_Loaded-event of the application:

GameInstance = new TeamBall.Game(this, PitchPanel);

我认为这与这个答案中给出的原则相同.

I think this is the same principle as given in this answer.

为什么这不起作用?有人知道如何从另一个线程调用控件吗?

So why does this not work? Does anybody know how to make calls to a control from another thread?

推荐答案

您不能在不同的线程上创建 WPF 对象 - 它也必须在 Dispatcher 线程上创建.

You cannot create a WPF object on a different thread - it must also be created on the Dispatcher thread.

这个:

System.Windows.Shapes.Ellipse PlayerEllipse = new System.Windows.Shapes.Ellipse();

必须进入委托.

这篇关于对 WPF 控件的线程安全调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆