通过单独的线程在表单上绘制

我正在尝试构建一个multithreading游戏,我在表单上有一个单独的线程,而不是主线程。 这给我们带来了线程安全的技术,我已经阅读了很多关于它的内容,但我不确定我是否正确使用了它。

我的问题是我有一个结构,每个数据对象都在表单上绘制它自己,所以我没有弄清楚如何实现它。

这是我工作的单线程代码的片段:

public partial class Form1 : Form { GameEngine Engine; public Form1() { InitializeComponent(); Engine = new GameEngine(); } protected override void OnPaint(PaintEventArgs e) { Engine.Draw(e.Graphics); } 

}

 class GameEngine { Maze Map; List Players; public void Draw(Graphics graphics) { Map.Draw(graphics); foreach (var p in Players) { p.Draw(graphics); } } 

}

所以,任何人都可以给我一个提示或链接到好文章,帮助我学习如何在另一个线程上分离绘图?

[编辑]

我设法实现了我打算做的事情,这就是我编写它的方式

  protected override void OnPaint(PaintEventArgs e) { formGraphics = e.Graphics; DisplayThread = new Thread(new ThreadStart(Draw)); DisplayThread.Start(); } private void Draw() { if (this.InvokeRequired) { this.Invoke(new DrawDelegate(this.Draw)); } else { Engine.Draw(formGraphics); } } 

但是我得到了一个ArgumentException:参数无效

请你指出该代码中的错误

我想你需要绘制一个Bitmap,然后在OnPaint方法中,将该位图绘制到窗口。 我马上就会certificate一下。

汉斯指出,在OnPaint方法中,你正在设置

 formGraphics = e.Graphics; 

但是在方法的最后,e.Graphics被处理掉了,所以你不能再使用它,如果你的代码到了

 Engine.Draw(formGraphics); 

你会得到一个例外。

所以基本上你需要有一个全球性的

 Bitmap buffer = new Bitmap(this.Width, this.Height) 

在你的asynced线程中,你可以调用你的绘图到你可以使用的位图

 Graphics g=Graphics.FromBitmap(buffer);// 

获取图形对象,但记住你必须这样做

 g.Dispose() 

它或包装在一个

 using (Graphics g=Graphics.FromBitmap(buffer)) { //do something here } 

我打算玩一会儿,看看我能不能给你一份工作样本

编辑这是你的工作样本。 我开始一个新的表格并在上面扔了一个按钮。 我将mainform backgroundimagelayout更改为none。

我认为您需要使用.net 4.0或更高版本,如果不使用它,请告诉我我可以更改它以匹配您的版本……我想。

 //you need this line to use the tasks using System.Threading.Tasks; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } public void Draw() { Bitmap buffer; buffer = new Bitmap(this.Width, this.Height); //start an async task Task.Factory.StartNew( () => { using (Graphics g =Graphics.FromImage(buffer)) { g.DrawRectangle(Pens.Red, 0, 0, 200, 400); //do your drawing routines here } //invoke an action against the main thread to draw the buffer to the background image of the main form. this.Invoke( new Action(() => { this.BackgroundImage = buffer; })); }); } private void button1_Click(object sender, EventArgs e) { //clicking this button starts the async draw method Draw(); } } 

}