Как показать прогресс загрузки с FTP - PullRequest
5 голосов
/ 24 февраля 2010

Я загружаю файл с FTP-сайта (Async) и мне нужно обновить индикатор выполнения.Я прочитал документацию MS, в которой говорится, что это можно сделать, если GetWebRequest () класса WebClient имеет ovverriden, поэтому для свойства «UsePassive» установлено значение «false».Я сделал это, но аргумент события «DownloadProgressChanged» ProgressPercentage всегда == '0'.

Может кто-нибудь сказать мне, как получить этот аргумент, чтобы начать возвращать значения?

Это метод загрузки:

            FTPClient request = new FTPClient();
            request.Credentials = new NetworkCredential(user, password);
            request.DownloadProgressChanged += UpdateProgress;
            request.DownloadFileAsync(ftpepath,destinationpath);

Это FTPClient (где я переопределяю GetWebRequest ()):

class FTPClient : WebClient 
    {
        protected override WebRequest GetWebRequest(System.Uri address)
        {
            FtpWebRequest req = (FtpWebRequest) base.GetWebRequest(address);
            req.UsePassive = false;
            return req;
        }
    }

И мой обратный вызов, если он помогает:

 void UpdateProgress(object sender, DownloadProgressChangedEventArgs e)
        {
            dwnProgress.Value = e.ProgressPercentage;
            dwnprcnt.Text = PercentProgress.ToString() + "%";
        }

Ответы [ 2 ]

3 голосов
/ 25 февраля 2010

UsePassive используется для «определения», кто выступает в роли сервера при установлении соединения для передачи файла, поэтому он не должен иметь никакого отношения к фактическому состоянию передачи. Могу я спросить, где вы это прочитали?

Может быть,

  • изменение очень маленькое для большого файла, поэтому вы не видите процентное соотношение?
  • что файл меньше внутреннего буфера ftpwebrequests, поэтому перед любым обновлением вы получаете весь файл?

Можете ли вы установить точку останова в UpdateProgress и увидеть что-либо в любом из свойств e?

И, как примечание, поскольку вы загружаете файл асинхронно, для фактической загрузки используется другой поток. В вашем методе события вы, вероятно, хотите сделать что-то вроде этого:

void UpdateProgress(object sender, DownloadProgressChangedEventArgs e) {
    setProgress(e.ProgressPercentage);
    setText(e.ProgressPercentage.ToString() + "%");
}

private void setProgress(int progress){
    if (dwnProgress.InvokeRequired) {
        dwnProgress.Invoke(new Action<int>(setProgress), progress);
        return;
    }
    dwnProgress.Value = progress;
}

private void setText(string text) {
   if (dwnprcnt.InvokeRequired) {
       dwnprcnt.Invoke(new Action<string>(setText), text);
       return;
   }
   dwnprcnt.Text = text;
}

Который будет ставить сетметоды в поток пользовательского интерфейса.

2 голосов
/ 19 апреля 2012

Я хотел оставить комментарий к вышеуказанному посту, но я слишком новый: (* ​​1001 *

Ссылка на MSDN при переопределении метода веб-запроса:

http://msdn.microsoft.com/en-US/library/system.net.webclient.downloadprogresschanged(v=vs.80).aspx

Однако в ответ на вопрос OPs, если ваш FTP-сервер не настроен на прием активных подключений, тогда установка WebClient.UsePassive = false не будет иметь значения.

РЕДАКТИРОВАТЬ: я включил System.Net.Tracing в моем проекте и пробовал как пассивный, так и активный режимы, и они не только работают как положено ... TotalBytes по-прежнему равен -1, поэтому я думаю, что ошибка в MSDN ошибочна чего-то не хватает

DownloadFileProgressChangedEventArgs содержит общее количество полученных байтов, и если вы знаете размер файла, вы можете рассчитать его самостоятельно.

Вероятно, есть лучший способ ... Но я использовал быстрый запрос FtpWebRequest, чтобы получить размер файла, а затем передал его в метод DownloadProgressCallback для обновления индикатора выполнения.

Кроме того, вышеупомянутый плакат не упоминается о том, что ваш метод прогресса обновления должен вызывать элемент управления, поскольку он вызывается потоком, созданным DownloadFileAsync, и вы можете изменить элемент управления только из потока, который его создал.

Вы должны использовать диспетчер для контроля, например,

if (!myCheckBox.Dispatcher.CheckAccess())
{
    myCheckBox.Dispatcher.BeginInvoke(new Action(
    delegate()
    {
        myCheckBox.IsChecked = true;
    }
    ));
}
else
{
    myCheckBox.IsChecked = true;
}

См. http://msdn.microsoft.com/en-us/library/ms591206.aspx

...