C# 新线程正在作为UI线程运行
我有一个表单DisplayImagesForm,它在构造函数中调用函数loadImages:C# 新线程正在作为UI线程运行,c#,multithreading,winforms,user-interface,C#,Multithreading,Winforms,User Interface,我有一个表单DisplayImagesForm,它在构造函数中调用函数loadImages: public ImageScraperForm(string query, RichTextBox textBox) { InitializeComponent(); this.query = query; loadImages(); } 然后loadImages函数在末尾创建一个新线程: { ... Thread thread = new Thread(readN
public ImageScraperForm(string query, RichTextBox textBox)
{
InitializeComponent();
this.query = query;
loadImages();
}
然后loadImages函数在末尾创建一个新线程:
{
...
Thread thread = new Thread(readNextImage);
thread.Start();
}
问题在于,该线程似乎不像UI线程那样作为不同的线程运行。readNextImage方法从服务器加载图像,这需要一些时间——加载图像时会阻塞整个表单。这是不正常的,因为线程应该与UI线程分开运行。readNextImage函数还可以修改UI元素,而无需调用MethodInvokerDelegate-不会引发异常。如果您试图通过internet下载图像并在WinForm控件中显示它;你完全错了 不要在表单构造函数中进行任何冗长的处理;这将使您的表单无响应。如果要在UI中显示某些内容,则应在窗体的Paint事件处理程序中显示。如果你试图通过互联网下载东西,你应该使用wait,而不是线程。线程使用一个CPU核心,由于互联网的速度比CPU慢几个数量级,您将立即阻止它 正确的方法是在需要时使用wait加载文件。如果在启动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);
}
从一个线程中获取交互式结果确实很困难。有更简单的方法可以做到这一点,但我们需要知道readNextImage的功能。它做文件或网络I/O吗?你应该使用wait。它是执行繁重的计算还是程序生成?您最好使用。这是Windows窗体。readNextImage进行网络I/O。没有繁重的计算,它只需下载图像作为流并在图片框中显示。您是否尝试创建计时器,如果该计时器在线程终止前熄灭,它会向您发送一条控制台消息,例如“未完成”,这样您就可以知道线程正在工作,但这项工作的成本比您想象的要高。我曾考虑在程序执行时使用perfmon应用程序,以查看在线程执行I/O工作时分配了多少资源!即使这样做是错误的,您也会在每次绘画活动中重新下载内容。绘制处理程序不是执行此操作的地方,如果必须选择,我将在加载的事件中执行此操作。\u img不会等于下一个绘制事件的null。好的,我错过了,但仍然是绘制事件?在这次事件中没有理由这样做。您从不使用PaintEventArgs,这是进入事件的唯一原因。如果你做了一些事情,比如说;我可以同意,但DoSomethingWith也不使用参数。最后,您不能安全地执行异步绘制事件,即PaintEventArgs,因此,当您使用eMy时,将处理等待返回e,如果您使用eMy示例未使用PaintEventArgs,但您是对的,如果使用了,则不起作用。我按照你的建议改为使用Load。