2015-10-17 124 views
-3

我有一个表格“DisplayImagesForm”,这在构造函数调用一个函数loadImages()新线程运行的UI线程

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 - 不会引发异常。

+1

从'Thread'返回交互结果真的很困难。有更简单的方法来做到这一点,但我们需要知道'readNextImage'的作用。它是否执行文件或网络I/O?你应该使用'await'。它是否执行繁重的计算或程序生成?使用['BackgroundWorker'](https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker%28v=vs.110%29.aspx)可能会更好。 –

+0

这是“Windows窗体”。 readNextImage执行网络I/O。没有繁重的计算,它只是将图像下载为流并显示在图片框中。 – Spejson

+0

您是否尝试制作计时器,如果该计时器在线程终止之前关闭,则会向您发送诸如“未完成”之类的控制台消息,以便您知道线程正在工作,但工作成本超过我的成本你会想。当你的程序执行时,我曾考虑过使用perfmon应用程序来查看当你的线程正在做I/O工作时分配了多少资源! –

回答

-2

如果您尝试通过互联网下载图像并将其显示在WinForm控件中;你完全错了。

不要在Form构造函数中做任何冗长的处理;这会让你的表单无法响应。如果您要在UI中显示某些内容,则应该在Form的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); 
} 
+0

即使这样做是错误的,你正在重新下载每个绘画事件的内容。油漆处理程序不是这样做的地方,如果我必须选择,我会在'Loaded'事件中执行此操作。 –

+0

_img不会等于下一个paint事件。 –

+0

好吧,我错过了,但仍然是油漆事件?没有理由在这个事件中。你永远不会使用'PaintEventArgs',这是唯一的原因在事件中。如果你已经完成了DoSomethingWith(_img,e);'我可以同意,但是DoSomethingWith也不会使用arg。 –