线程安全调用WPF控件

时间:2012-10-29 19:48:04

标签: c# wpf xaml stackpanel

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

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

这很好用,我可以通过Window.Loaded事件访问名为PitchPanel的Canvas。

现在我添加了一个名为Game的类,它被初始化为:

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的主题。这应该以最高可能的速率重绘当前游戏状态,如下所示:

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],内部异常表示我无法访问该对象它由另一个线程(主线程)拥有。

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

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

我认为这与this answer中给出的原则相同。

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

1 个答案:

答案 0 :(得分:1)

您无法在其他线程上创建WPF对象 - 它也必须在Dispatcher线程上创建。

此:

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

必须进入代表。