防止形式冻结

时间:2009-08-24 13:26:10

标签: c# .net winforms multithreading

我想下载图片,然后将其显示在图片框中。

起初我确实喜欢这个:

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方法将文件下载到文件中。

解决这个问题的最佳等待是什么?

4 个答案:

答案 0 :(得分:13)

基本上,最初发生的事情是UI Thread正在完成下载,并且因为它正在解决这个问题,所以它无法刷新或绘制(同步工作)。现在发生的事情是你正在启动线程然后UI线程继续,然后尝试将本地文件(尚未完成下载)分配到图片框。您应该尝试以下任一方法:

您应该使用background worker来完成下载任务。

它有非常方便的事件。 DoWork,您可以在那里开始下载。

当Work完成时,还会触发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 :(得分:2)

最简单的解决方案是使用Picturebox.LoadAsync()方法,让Picturebox担心在后台加载它。如果您需要检查错误,请使用LoadCompleted事件(图片框)。

像:

这样的一行
pictureBox1.LoadAsync(@"http://imgs.xkcd.com/comics/tech_support_cheat_sheet.png");

就是你所需要的一切。

答案 2 :(得分: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线程后,打开文件并根据需要更新UI(IE:重新启用字段等)。

皮革。

答案 3 :(得分:1)

与线程问题无关,但如果您没有将照片保存到磁盘的任何其他要求,则可以执行此操作:

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