我想下载图片,然后将其显示在图片框中。
起初我确实喜欢这个:
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方法将文件下载到文件中。
解决这个问题的最佳等待是什么?
答案 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;