简体   繁体   English

防止形式冻结

[英]Prevent form from freezing

I'd like to download a picture and afterwards show it in a picturebox. 我想下载一张图片然后在图片框中显示。

at first I did like this: 起初我喜欢这样:

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

But that wasn't perfect because for the time while the download is performed the app is kinda freezing. 但这并不完美,因为在执行下载的时候,应用程序有点冷冻。

Then I changed to this: 然后我改为:

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);
    }

But now I have to do something like a "wait for thread ending" because the file is accessed in the thread and to same time there's downloaded something to the file by the DownloadMap method. 但现在我必须做一些类似“等待线程结束”的事情,因为文件是在线程中访问的,同时也是通过DownloadMap方法将文件下载到文件中。

What would be the best wait to solve that problem? 什么是解决这个问题最好的等待?

Basically, What was happening originally, was the UI Thread was completing the download, and because it was working away on that, it couldn't be refreshed or painted (working synchronously). 基本上,最初发生的是UI线程正在完成下载,并且因为它正在解决这个问题,它无法刷新或绘制(同步工作)。 Now what is happening is that you're starting the thread then the UI thread is continuing, then trying to assign the local file (which hasn't finished downloading) to the picture box. 现在发生的事情是你正在启动线程然后UI线程继续,然后尝试将本地文件(尚未完成下载)分配到图片框。 You should try either of the following: 您应该尝试以下任一方法:

You should use a background worker to complete your download task. 您应该使用后台工作程序来完成下载任务。

It has events that will be very handy. 它有非常方便的事件。 DoWork, where you can start the download. DoWork,您可以在其中开始下载。

There is also a RunWorkerCompleted event that is fired when the Work has completed. 还有一个RunWorkerCompleted事件,在Work完成时触发。 Where you can set the image there ( pictureBox2.Picture = localFile; ). 你可以在那里设置图像( pictureBox2.Picture = localFile; )。

It's definitely worth checking out, I think it's the most appropriate way to complete what you are trying to achieve. 这绝对值得一试,我认为这是完成你想要实现的目标的最合适的方式。

Or 要么

If you want to stick with using a Thread. 如果你想坚持使用线程。 You could take out the Image assignment after you've done the Thread.Start() , and put this in to your Worker Thread function: 在完成Thread.Start() ,您可以取出Image赋值,并将其放入您的Worker Thread函数中:

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;
  }
}

The simplest solution would be to just use the Picturebox.LoadAsync() method and let the Picturebox worry about loading it in the background. 最简单的解决方案是使用Picturebox.LoadAsync()方法,让Picturebox担心在后台加载它。 If you need to check for errors, use the LoadCompleted event (of the picturebox). 如果需要检查错误,请使用LoadCompleted事件(图片框)。

A line like: 像这样的一行:

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

is all you need. 是你所需要的全部。

When the user initiates the process what you need to do is: 当用户启动该过程时,您需要做的是:

1) Update the UI to indicate something is happening. 1)更新UI以指示正在发生的事情。 IE: Disable all the fields and put up a message saying "I am downloading the file, please wait...". IE:禁用所有字段并发出一条消息“我正在下载文件,请稍候......”。 Preferentially with some kind of progress indicator (sorry I am not sure if the WebClient supports progress etc but you need to update the UI as the download make take a while). 优先使用某种进度指示器(抱歉,我不确定WebClient是否支持进度等,但您需要更新UI,因为下载需要一段时间)。

2) Attach an event handler to the WebClient's 'DownloadFileCompleted'. 2)将事件处理程序附加到WebClient的“DownloadFileCompleted”。

3) Use the WebClient's DownloadFileAsync method to start the download on another thread. 3)使用WebClient的DownloadFileAsync方法在另一个线程上开始下载。 You don't need to spin threads up yourself. 你不需要自己旋转线程。

4) When the 'DownloadFileCompleted' event is fired route the call back to the UI thread by using the form's invoke method. 4)当触发'DownloadFileCompleted'事件时,使用表单的invoke方法将调用路由回UI线程。 THIS IS VERY IMPORTANT. 这个非常重要。

See: http://weblogs.asp.net/justin_rogers/pages/126345.aspx 请参阅: http//weblogs.asp.net/justin_rogers/pages/126345.aspx

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

5) Once the event has been routed back onto the UI thread open the file and update the UI as required (IE: Re-enable fields etc). 5)一旦事件被路由回UI线程,打开文件并根据需要更新UI(IE:重新启用字段等)。

Leather. 皮革。

Not related to the threading issue, but if you don't have any other requirements for saving the photo to the disk you can do this: 与线程问题无关,但如果您没有将照片保存到磁盘的任何其他要求,则可以执行以下操作:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM