如何更新不同线程中的组件? .NET CF
我正在对.NET Compact Framework应用程序进行编程,该应用程序在PDA上显示地图。
Ive创建了一个临时组件,该组件绘制了自己的整个地图,并使用其中的几个组成了大图片。我这样做是为了避免一步一步绘制整个地图的等待时间。
我想知道的是将这些片段绘制在自己的线程中,因此地图似乎会作为单个实体增长,并且(而且,更重要的是)避免冻结用户界面的其余部分。
知道地图的每个部分都是用其onPaint方法绘制的。我的想法是以某种方式告诉系统"请在线程中执行此代码"。
就像是:
protected override void OnPaint(PaintEventArgs e) { // <code to be executed in a thread> e.Graphics.paintTHis(); e.Graphics.paintThat(); whateverItTakesToPaintThisPieceOfTheMap(); // </code to be executed in a thread> }
你知道怎么做吗?还是我的方法完全错误?
谢谢你的时间!
解决方案
该方法是错误的。更新ui的代码必须在ui线程上运行。如果我们从另一个线程更新ui,则会出现异常。
我建议我们使用从底层线程到主UI线程的某种消息传递系统。
这样,主UI线程进行所有更改,并从基础线程触发。另外,如果要将一些复杂的信息发送回主UI线程,请确保可以随这些消息一起发送一些数据。
为了调用从另一个线程更新UI的函数,请使用Form的Invoke函数。
这是一个很好的参考
http://weblogs.asp.net/justin_rogers/articles/126345.aspx
编辑:如注释中指出的那样,如果我们希望调用代码不等待UI线程,BeginInvoke会更好。
在后台线程中在内存中绘制地图,然后在准备好时(在UI线程中)将该光栅图像渲染到屏幕上。如果可能,请使用BufferedGraphics,否则请使用GDI。
如果渲染地图非常耗时,并且我们不想冻结GUI线程(使应用程序无响应),则可以将屏幕划分为多个单元格。使用后台线程将单元格渲染为位图,使用"调用"告诉GUI线程绘制完成的单元格,当调用返回时,让线程继续下一个单元格。
我们将需要直接在控件上绘制(不在Paint()内部),或者需要调用invalidateRect并具有一些逻辑以确保我们计算出的图像与系统希望我们绘制的图像匹配。
这将使图像逐渐出现,并且UI会响应。如果用户采取某种措施使其不必继续绘制,则只需中止线程即可。