Получить прогресс асинхронного вызова

Я использую блок кода, полученный из блога, для загрузки изображений в IMGur с помощью API v3.

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

Пока мне не удалось этого сделать.

Я не опытный программист, просто делаю это в качестве учебного проекта.

Код:

public object UploadImage(string image) 
{ 
    WebClient w = new WebClient();
    w.UploadProgressChanged += (s, e) => { };
    w.UploadValuesCompleted += (s, e) => { };
    w.Headers.Add("Authorization", "Client-ID " + ClientId);
    System.Collections.Specialized.NameValueCollection Keys = new System.Collections.Specialized.NameValueCollection(); 
    try 
    { 
        Keys.Add("image", Convert.ToBase64String(File.ReadAllBytes(image))); 
        byte[] responseArray = w.UploadValues("https://api.imgur.com/3/image", Keys);


        dynamic result = Encoding.ASCII.GetString(responseArray); System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex("link\":\"(.*?)\""); 
        System.Text.RegularExpressions.Match match = reg.Match(result); 
        string url = match.ToString().Replace("link\":\"", "").Replace("\"", "").Replace("\\/", "/");
        textBox1.Text = url;
        return url; 
    }
    catch (Exception s) 
    { 
        MessageBox.Show("Something went wrong. " + s.Message); 
            return "Failed!"; 
    } 
}

Сначала я попытался использовать события UploadProgressChanged и UploadValuesCompleted, но они не запускаются, моя теория заключается в том, что они запускаются, когда UploadValuesAsync вызывается вместо UploadValues.

  1. Как мне внедрить систему прогресса?
  2. В чем разница между асинхронной и нормальной передачей?

person RiskyTitle    schedule 24.03.2014    source источник


Ответы (1)


Разница между aync и нормальной передачей заключается в том, что метод UploadValues блокирует текущий поток до тех пор, пока не будут переданы все данные. Поскольку в это время поток заблокирован, вы также не можете поймать никаких событий. Поэтому вы должны использовать метод асинхронности UploadValuesAsync, который будет передавать данные в фоновом режиме, и вы сможете продолжить выполнение своего кода.
UploadProgressChanged также срабатывает только для UploadValuesAsync. Ваш код должен выглядеть примерно так (Не проверено!):

public String UploadImage(string image) 
    { 
        WebClient w = new WebClient();

        w.UploadProgressChanged += (s, e) =>
        {
            myProgressBar.Maximum = (int)e.TotalBytesToSend;
            myProgressBar.Value = (int)e.BytesSent;
        };

        w.UploadValuesCompleted += new UploadValuesCompletedEventHandler(UploadComplete);

        w.Headers.Add("Authorization", "Client-ID " + ClientId);
        System.Collections.Specialized.NameValueCollection Keys = new System.Collections.Specialized.NameValueCollection(); 
        try 
        { 
            Keys.Add("image", Convert.ToBase64String(File.ReadAllBytes(image))); 
            w.UploadValuesAsync("https://api.imgur.com/3/image", Keys);

            return "Uploading..";
        } catch (Exception s) 
        { 
            MessageBox.Show("Something went wrong. " + s.Message); 
                return "Failed!"; 
        } 
    }

public void UploadComplete(Object sender, UploadValuesCompletedEventArgs e)
{
    myProgressBar.Value = 100;

    byte[] responseArray = e.Result;
    dynamic result = Encoding.ASCII.GetString(responseArray); 
    System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex("link\":\"(.*?)\""); 
    System.Text.RegularExpressions.Match match = reg.Match(result); 
    string url = match.ToString().Replace("link\":\"", "").Replace("\"", "").Replace("\\/", "/");
    textBox1.Text = url;
}

Изменить
Я переместил код после вызова UploadValuesAsync в w.UploadValuesCompleted. Вы можете найти ответ сервера в поле Result класса UploadValuesCompletedEventArgs, которое передается событию в переменной e.
Ваш метод UploadImage теперь вернет Загрузка, когда начнется процесс, и вы в событии w.UploadValuesCompleted придется делать свой отдых.

person Kimmax    schedule 25.03.2014
comment
UploadValuesAsync возвращает void, а UploadValues ​​возвращает массив байтов. Какие-нибудь предложения? - person RiskyTitle; 26.03.2014
comment
Возможно, вам потребуется переместить код после вызова UploadValuesAsync в обработчике событий UploadValuesCompleated и прочитать результат из e.Result. Я обновлю свой ответ, как только вернусь домой. - person Kimmax; 26.03.2014
comment
Хорошо, я обновил свой код, но все еще не протестирован. Сообщите мне, работает ли это - person Kimmax; 26.03.2014
comment
Большое спасибо! Ваш код не работал, но он указал мне правильное направление, спасибо !, e.Result () возвращает byte [] вместо строки, поэтому я взял его в старый массив bytearray responseArray, и он работал безупречно. Я хочу отметить, что e.ProgressPercentage не работает; Я использовал myProgressBar.Maximum = (int) e.TotalBytesToSend; myProgressBar.Value = (число) e.BytesSent; - person RiskyTitle; 26.03.2014
comment
Кстати, для эффективности кода и удобства чтения, что лучше использовать лямбда-выражения или обычную структуру, подобную методам? - person RiskyTitle; 26.03.2014
comment
Да, вы правы, e.Result возвращает строку в случае UploadStringCompleted, я пропустил это. Я думаю, вам следует использовать обычный метод в вашем случае, потому что его легче читать, потому что у вас есть еще код в этом лямбда-блоке. Я выбираю лямбды для очень короткого кода, как показано в вашем блоке w.UploadProgressChanged и обычных методах, если мне нужно там еще поработать. Я обновил свой код, чтобы он стал функциональным. - person Kimmax; 26.03.2014