新线程作为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——不会抛出异常。

新线程作为UI线程运行

如果你试图通过互联网下载图像并在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);
}