2009-08-24 26 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スレッドがダウンロードを完了していて、それを取り除いていたために、リフレッシュまたはペイント(同期的に動作)できませんでした。さて、あなたはスレッドを開始してから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).Invoke();あなたの長期的な機能の中でBeginInvokeによってあなたのGUI要素を更新してください。 GUIスレッドから何かがあるかどうかを判断するには、backgroundWorker.IsBusyをチェックします。 – Oliver

+0

詳細については、以下をご覧ください。http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx – Oliver

+0

@Oliver:真実、彼らはかなり開発者フレンドリーです、彼らはたくさんのことをしています私たちの仕事。 – ThePower

2

最も簡単な解決策はただPicturebox.LoadAsync()メソッドを使用してロードについてのPictureBox心配をできるようになりますそれは背景にある。エラーをチェックする必要がある場合は、(ピクチャボックスの)LoadCompletedイベントを使用します。

行のような:

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

はあなたが必要とするすべてです。

1)が起こっている何かを示すためにUIを更新します。ユーザーは、あなたが何をする必要があるかのプロセスを開始

1

。 IE:すべてのフィールドを無効にして、「ファイルをダウンロードしています、お待ちください...」というメッセージを表示してください。優先的に何らかの進捗インジケータがあります(申し訳ありませんが、WebClientが進捗状況などをサポートしているかどうかはわかりませんが、ダウンロードには時間がかかるためUIを更新する必要があります)。

2)WebClientの 'DownloadFileCompleted'にイベントハンドラをアタッチします。

3)WebClientのDownloadFileAsyncメソッドを使用して、別のスレッドでダウンロードを開始します。スレッドを自分自身でスピンアップする必要はありません。

4) 'DownloadFileCompleted'イベントが発生すると、フォームの呼び出しメソッドを使用してUIスレッドにコールバックをルーティングします。これはとても重要です。

参照:http://weblogs.asp.net/justin_rogers/pages/126345.aspx

と:再度有効フィールドなど):http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

5)イベントがUIスレッドファイルを開き、必要に応じてUIを更新(IE上に戻してルーティングされた後。

革。

+0

はい、WebClientにはDownloadProgressChangedイベントとDownloadCompletedイベントがあります –

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

+0

不要なファイルでディスクを混乱させません。特にファイルが大きい場合。 –

+0

これは、同じ写真を繰り返しダウンロードすることがない場合にのみ便利です。その場合は、ディスクに保存して、それらを再度ダウンロードする前に存在するかどうかを確認する方が効率的です。 –

関連する問題