新线程作为UI线程运行
本文关键字:线程 UI 运行 新线程 | 更新日期: 2023-09-27 18:18:05
我有一个表单"DisplayImagesForm",它在构造函数中调用函数loadImages()
:
public ImageScraperForm(string query, RichTextBox textBox)
{
InitializeComponent();
this.query = query;
loadImages();
}
然后loadImages()
函数在末尾创建一个新线程:
{
...
Thread thread = new Thread(readNextImage);
thread.Start();
}
问题是线程似乎没有作为一个不同的线程运行,而不是UI线程。readNextImage()
方法从服务器加载图像,这需要一些时间-当加载图像时,它会阻塞整个表单。这是不正常的,因为"线程"应该与UI线程分开运行。另外,readNextImage()
函数可以修改UI元素而不需要Invoke((MethodInvoker)delegate
——不会抛出异常。
如果你试图通过互联网下载图像并在WinForm控件中显示它;你完全错了。
不要在Form构造函数中做任何冗长的处理;这将使您的表单无响应。如果你要在UI中显示一些东西,你应该在窗体的Paint事件处理程序中这样做。如果你想通过互联网下载一些东西,你应该使用await
,而不是Thread
。线程使用CPU内核,由于互联网比CPU慢几个数量级,因此您将立即阻塞它。
这样做的正确方法是使用await
加载文件时,你需要它。如果您在启动Load
事件处理程序时需要它,这是一个不错的选择。
private async void YourForm_Load(object sender, EventArgs e)
{
using (var c = new HttpClient())
using (var resp = await c.GetAsync(@"http://uri/to/image.jpg"))
using (var content = resp.Content)
using (var s = await content.ReadAsStreamAsync())
{
_img = new Bitmap(s);
}
YourControl.Invalidate();
}
private void YourForm_Paint(object sender, PaintEventArgs e)
{
if (_img != null)
DrawToYourControl(_img);
}