2009-08-24 105 views
3

我想下載一張圖片,然後將其顯示在圖片框中。防止表單凍結

起初我是這樣的:

WebClient client = new WebClient(); 
client.DownloadFile(url, localFile); 
pictureBox2.Picture = localFile; 

不過,這不是完美的,因爲對時間,而下載執行應用程序被凍結還挺。

後來我改成這樣:

public class ParamForDownload 
{ 
    public string Url { get; set; } 
    public string LocalFile { get; set; } 
} 
ParamForDownload param = new ParamForDownload() 
     { 
      Url = url, 
      LocalFile = localFile 
     }; 

     ThreadStart starter = delegate { DownloadMap (param); }; 
     new Thread(starter).Start(); 

     pictureBox2.Picture = localFile; 



    private static void DownloadMap(ParamForDownload p) 
    { 
     WebClient client = new WebClient(); 
     client.DownloadFile(p.Url, p.LocalFile); 
    } 

但現在我必須做一些像「等待結束線程」,因爲該文件在線程和同時還有的下載東西的文件訪問通過DownloadMap方法。

解決這個問題最好等待什麼?

回答

13

基本上,最初發生的事情是UI Thread正在完成下載,並且因爲它正在工作,所以無法刷新或繪製(同步工作)。現在發生的是你開始線程,然後UI線程繼續,然後試圖將本地文件(尚未完成下載)分配給圖片框。您應該嘗試以下任一方法:

您應該使用background worker完成您的下載任務。

它具有非常方便的事件。 DoWork,在那裏你可以開始下載。

還有一個RunWorkerCompleted事件在工作完成時觸發。你可以在那裏設置圖像(pictureBox2.Picture = localFile;)。

這絕對值得一試,我認爲這是完成您嘗試實現的最合適的方式。

或者

如果你想堅持使用線程。你可以拿出圖像任務,你已經做了Thread.Start()後,並把這個在您的工作線程功能:

private delegate void MyFunctionCaller(); 

private static void DownloadMap(ParamForDownload p) 
{ 
    WebClient client = new WebClient(); 
    client.DownloadFile(p.Url, p.LocalFile); 
    DownloadMapComplete(p); 
} 

private void DownloadMapComplete(ParamForDownload p) 
{ 
if (InvokeRequired == true) 
    { 
    MyFunctionCaller InvokeCall = delegate { DownloadMapComplete(p); }; 
    Invoke(InvokeCall); 
    } 
else 
    { 
    pictureBox2.Picture = p.LocalFile; 
    } 
} 
+1

BackgroundWorker的肯定是你正在尋找的東西。我剛剛使用它,它使用起來非常簡單。只需在DoWork事件中添加一些內容,將結果放入e.Result並在RunWorkerCompleted事件中使用此值。或者,如果您的長時間運行的函數更復雜,請在((MethodInvoker)e.Argument)中調用它們。並在您的長時間運行功能中通過BeginInvoke更新您的GUI元素。要從GUI線程確定是否有什麼事情發生,你可以檢查backgroundWorker.IsBusy; – Oliver 2009-08-24 13:59:47

+0

欲瞭解更多信息,請看:http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx – Oliver 2009-08-24 14:00:27

+0

@Oliver:真的,他們非常適合開發者,他們做了很多我們的工作。 – ThePower 2009-08-24 14:01:35

2

最簡單的解決辦法是隻使用Picturebox.LoadAsync()方法,讓有關加載PictureBox的憂慮它在後臺。如果您需要檢查錯誤,請使用(圖片框的)LoadCompleted事件。

這樣一行:

pictureBox1.LoadAsync(@"http://imgs.xkcd.com/comics/tech_support_cheat_sheet.png"); 

是你所需要的。

1

當用戶發起,你需要做的過程是:

1)更新UI,表示事情正在發生。 IE瀏覽器:禁用所有字段,並提示「我正在下載文件,請稍候......」。優先使用某種進度指示器(抱歉,我不確定WebClient是否支持進度等,但您需要在下載過程中更新UI)。

2)將事件處理程序附加到WebClient的'DownloadFileCompleted'。

3)使用WebClient的DownloadFileAsync方法在另一個線程上開始下載。你不需要自己旋轉線程。

4)當'DownloadFileCompleted'事件被觸發時,通過使用表單的invoke方法調用回UI線程。這個非常重要。

參見:http://weblogs.asp.net/justin_rogers/pages/126345.aspx

和:http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

5)一旦事件已被路由返回到UI線程打開該文件,並根據需要更新用戶界面(IE:重新啓用字段等)。

皮革。

+0

是的,WebClient有DownloadProgressChanged和DownloadCompleted事件 – 2009-08-24 13:40:19

1

不相關的線程問題,但如果你沒有的照片保存到你可以做到這一點磁盤的所有其他要求:

WebClient client = new WebClient(); 
byte[] data = client.DownloadData(item.Url); 
MemoryStream ms = new MemoryStream(data); 
Bitmap img = new Bitmap(ms); 
pictureBox.Image = img; 
+0

有什麼優勢? – Kai 2009-08-24 13:43:28

+0

不會使用不需要的文件混淆磁盤。特別是如果文件很大。 – 2009-08-24 13:46:14

+0

這隻有在您不會一遍又一遍下載相同的照片時纔有用,在這種情況下,將它們保存到磁盤並在再次下載之前檢查它們是否存在將會更有效。 – 2009-08-24 13:48:00