我正在使用C#开发一个从互联网下载文件的应用程序(我不想使用后台下载程序!) 这是下载的类代码:
public class DL
{
public event Progresses OnProgress;
Stopwatch stopwatch = new Stopwatch();
public async void Get(string url, StorageFile destinationFile)
{
stopwatch.Reset();
stopwatch.Start();
HttpWebRequest request = (HttpWebRequest)WebRequest.
Create(url);
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
long size = response.ContentLength;
long downloaded = 0;
using (Stream inputStream = response.GetResponseStream())
using (Stream outputStream = await destinationFile.OpenStreamForWriteAsync())
{
byte[] buffer = new byte[1024];
int bytesRead;
do
{
bytesRead = inputStream.Read(buffer, 0, buffer.Length);
downloaded += bytesRead;
outputStream.Write(buffer, 0, bytesRead);
int secondsRemaining = (int)(stopwatch.Elapsed.TotalSeconds
/ downloaded * (size - downloaded));
TimeSpan span = new TimeSpan(0, 0, 0, secondsRemaining);
string remainTime = string.Format("{0}:{1}:{2}", span.Hours, span.Minutes, span.Seconds);
OnProgress(remainTime);
} while (bytesRead != 0);
}
}
}
public delegate void Progresses(string text);
这就是下载文件的方法:
private async void btnDownload_Click(object sender, RoutedEventArgs e)
{
DL webGard = new DL();
webGard.OnProgress += WebGard_OnProgress;
StorageFile destinationFile = await KnownFolders.MusicLibrary
.CreateFileAsync("r58.zip", CreationCollisionOption.GenerateUniqueName);
string url = "my url";
webGard.Get(url, destinationFile);
}
private async void WebGard_OnProgress(string text)
{
System.Diagnostics.Debug.WriteLine(text);
var dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
textBlock.Text = text;
});
}
当我按下下载按钮时,应用程序当前进入挂起并且无法使用它直到下载结束,我想向用户显示剩余时间,此代码适用于visual studio中的输出窗口但是UI被挂起而且不能在textBlock中显示结果。
如何解决此问题? 感谢
答案 0 :(得分:1)
这里的问题是你正在使用所有正确的异步命令来启动,这很棒。不幸的是,当您实际从流中读取数据时,您将同步执行此操作。这就是我的意思......
初始化流后,您将开始使用循环读取和写入数据。如果查看do / while循环,您将看到所有操作都是同步完成的。此循环中有两个工作项导致您的重要应用程序挂起。这一行:
bytesRead = inputStream.Read(buffer, 0, buffer.Length);
和这一行:
outputStream.Write(buffer, 0, bytesRead);
在循环的每次迭代期间,当您等待来自服务器的带有下一个数据块的响应时,您将阻止应用程序线程。这意味着您不仅要等待服务器回复,还要等待通过网络传输此数据的延迟。除此之外,当您将此数据写回文件时,您将被文件系统阻止。相反,您应该使用流的ReadAsync和WriteAsync方法。
这样,实际上只在实际上在内存中移动数据时,只会在很短的时间内阻塞主线程。然后你回到等待流来完成他们的操作,同时你的应用程序UI线程可以自由地做它想要的。
我希望这有帮助!