2015-10-17 204 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。 –