Если вы не удосужились прочитать весь текст, вы можете перейти к двум последним точкам: p
Этот сайт уже несколько раз помогал мне в прошлом, но теперь мне действительно нужна помощьсебя.
сначала я использовал функцию DownloadFile с опцией show UI.Это прекрасно работало, но пользовательский интерфейс уродлив, и не так много вариантов.
Затем я переключился на DownloadFileAsync с измененным событием прогресса, чтобы в основном иметь свой собственный пользовательский интерфейс.Единственная проблема, с которой я столкнулся, заключается в том, что я перебираю список файлов, которые должна загрузить программа, и вызываю функцию загрузки (которая вызывает функцию DownloadAsync).Например:
foreach (ListViewItem t in themeList.CheckedItems)
{
DownloadFile(file to be downloaded);
}
Но, очевидно, это не сработало, так как функция DownloadFileAsync не поддерживает несколько вызовов одновременно, потому что нет такой системы очередей, как DownloadFile,поэтому он будет загружать только первый вызванный файл.Итак, я сделал функцию, которая добавляет файл для загрузки в массив и выполняет фоновый цикл по списку и ждет вызова DownloadAsync до завершения предыдущей загрузки.Это вроде сработало.Вот код:
#region "Download functions"
//Function that converts download speed to a nice user friendly format
private static string BpsToString(double bps)
{
var m = new string[] { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
var i = 0;
while (bps >= 0.9 * 1024)
{
bps /= 1024;
i++;
}
return String.Format("{0:0.00} {1}/sec", bps, m[i]);
}
private bool _complete = false;
private string _speed;
private int _secondsRemaining = -1;
private long _transferred = 0;
private Stopwatch _sw = new Stopwatch();
private List<string[]> _fd = new List<string[]>();
private void DownloadFile(string url, string des, bool overwrite = false)
{
if (overwrite) //if the file needs to be overwritten or not
{
if (File.Exists(des)) File.Delete(des);
}
else
{
if (File.Exists(des)) return;
}
if (!Directory.Exists(Path.GetDirectoryName(des))) //create the directory if it doesn't exist
Directory.CreateDirectory(Path.GetDirectoryName(des));
string[] file = {url, des};
_fd.Add(file); //add file to queue list
if(!backgroundDownloader.IsBusy) //if downloader isn't doing anything, start it again
backgroundDownloader.RunWorkerAsync();
}
//function called by the backgroundworker to actually download the file
private void ContinueDownloadFile(string url, string des)
{
var webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
webClient.DownloadFileAsync(new Uri(_fd[0][0]), _fd[0][1]);
}
//when download completed, set progress bar to 0% and remove the first (0) download from the queue
private void Completed(object sender, AsyncCompletedEventArgs e)
{
SetProgressText("Idle");
SetProgressValue(0);
if(_fd.Count != 0)
_fd.RemoveAt(0);
_complete = true; //if it's complete, set to true so the backgroundworker knows it can start the next download
}
//progress bar value change and status change for download speed etc...
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
if(progressLabel.Text == "Idle")
SetProgressText("Downloading...");
if (_sw.Elapsed >= TimeSpan.FromSeconds(1))
{
_sw.Stop();
var bytes = e.BytesReceived - _transferred;
var bps = bytes * 1000.0 / _sw.Elapsed.TotalMilliseconds;
_speed = BpsToString(bps);
_secondsRemaining = (int)((e.TotalBytesToReceive - e.BytesReceived) / bps);
_transferred = e.BytesReceived;
_sw.Reset();
_sw.Start();
SetProgressText("Downloading: " + e.ProgressPercentage + "% | Seconds remaining: " +
_secondsRemaining + " | Files remaining: " + _fd.Count + " | Speed: " + _speed);
}
SetProgressValue(e.ProgressPercentage);
}
//the backgroundworker who starts the downloads from the list one by one
private void BackgroundDownloaderDoWork(object sender, DoWorkEventArgs e)
{
while (_fd.Count != 0)
{
_sw.Start();
_complete = false; //let the backgroundworker wait till the download is complete
ContinueDownloadFile(_fd[0][0], _fd[0][1]);
while(!_complete) //let it wait here
Thread.Sleep(100);
_sw.Stop();
_sw.Reset();
}
}
#endregion
Итак, в принципе, моя следующая проблема заключается в том, что программе придется ждать выполнения кода, пока загрузка не будет завершена.Я сделал это, выполнив:
while (_fd.Count != 0)
Application.DoEvents();
Это, очевидно, не лучшее решение, поскольку они могут щелкать другие объекты, пока загружаются файлы, но да, Thread.Sleep просто заморозит все,Вместо этого я бы сделал форму ожидания (возможно, здесь индикатор выполнения вместо главной формы) с фокусом на ней поверх основной формы, чтобы они не могли щелкнуть основную форму и поместить Thread.Sleep в основную форму.?
Как бы вы решили это?Вы бы также использовали фонового работника, который проходит по массиву файлов или есть более простой и эффективный способ.Может быть, не с помощью DownloadFileAsync, а с ручной загрузкой сокетов?
В основном я хочу загружать файлы синхронно, но иметь свой собственный пользовательский интерфейс (поэтому мне нужно использовать асинхронные функции загрузки).Хаха
Надеюсь, я вас достаточно проинформировал.Заранее спасибо.