WebClient.DownloadDataAsync замораживает мой пользовательский интерфейс - PullRequest
6 голосов
/ 07 ноября 2008

У меня есть в конструкторе форм, после InitializeComponent следующий код:

using (WebClient client = new WebClient())
{
    client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
    client.DownloadDataAsync("http://example.com/version.txt");
}

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

Что я делаю не так? Как это сделать, не заморозив интерфейс?

Спасибо за ваше время.
С наилучшими пожеланиями.

ПОЛНЫЙ КОД:

Program.cs

using System;
using System.Windows.Forms;

namespace Lala
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Form1.cs

using System;
using System.Net;
using System.Windows.Forms;

namespace Lala
{
    public partial class Form1 : Form
    {
        WebClient client = new WebClient();

        public Form1()
        {
            client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
            client.DownloadDataAsync(new Uri("http://www.google.com"));
            InitializeComponent();
        }

        void client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
        {
            textBox1.Text += "A";
        }
    }

    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(12, 12);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(75, 23);
            this.button1.TabIndex = 0;
            this.button1.Text = "button1";
            this.button1.UseVisualStyleBackColor = true;
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(12, 41);
            this.textBox1.Multiline = true;
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(468, 213);
            this.textBox1.TabIndex = 1;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(492, 266);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.TextBox textBox1;
    }
}

Ответы [ 16 ]

5 голосов
/ 06 апреля 2014

Обнаружил ту же проблему и нашел решение. Довольно сложное обсуждение здесь: http://social.msdn.microsoft.com/Forums/en-US/a00dba00-5432-450b-9904-9d343c11888d/webclient-downloadstringasync-freeze-my-ui?forum=ncl

Короче говоря, проблема в том, что веб-клиент ищет прокси-серверы и вывешивает приложение. Помогает следующее решение:

WebClient webClient = new WebClient();
webClient.Proxy = null;
... Do whatever else ...
4 голосов
/ 07 ноября 2008

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

У меня есть небольшая запись в журнале, чтобы указать непосредственно до и после вызовов DownloadDataAsync, и когда запускается завершенный обработчик. Если я загружаю большой файл через 3G, - это пауза между «до» и «после», но пользовательский интерфейс появляется задолго до завершения загрузки файла.

У меня есть подозрение, что connect выполняется синхронно, но фактическая загрузка выполняется асинхронно. Конечно, это по-прежнему прискорбно - и, возможно, стоит добавить все это в другую ветку - но если я прав, по крайней мере, об этом стоит знать.

1 голос
/ 05 апреля 2011

попробуйте это:

client.Proxy = GlobalProxySelection.GetEmptyProxy();
1 голос
/ 20 мая 2010

Я только что протестировал то же самое в проекте WPF под VS2010, .NET 4.

Я загружаю файл с индикатором выполнения, чтобы показать процент выполнения, используя WebClient.DownloadDataCompleted и т. Д.

И, к моему изумлению, я обнаружил то же самое, что упомянул @Dan: Внутри отладчика он забавным образом блокирует поток. В режиме отладки мой индикатор прогресса обновляется на 1%, затем некоторое время ничего не делает, а затем снова обновляется внезапно на 100%. (Операторы Debug.WriteLn печатаются плавно повсюду). И между этими двумя временами пользовательский интерфейс заморожен.

Но вне отладчика индикатор выполнения плавно перемещается от 0% до 100%, и пользовательский интерфейс никогда не зависает. Это то, что вы ожидаете.

1 голос
/ 27 ноября 2008

DownloadDataAsync и DownloadData в потоке без пользовательского интерфейса:

DownloadDataAsync полезен тем, что фактически не связывает поток до обработки DownloadDataCompletedEvent после того, как запрос был сделан и сервер отвечает.

Я считаю, что Джон Скит находится на правильном пути - я читал, что разрешение DNS должно завершиться синхронно, прежде чем асинхронный HTTP-запрос будет поставлен в очередь, и вызов DownloadDataAsync вернется.

Может ли разрешение DNS быть медленным?

1 голос
/ 07 ноября 2008

Я сильно подозреваю, что это связано с удалением WebClient, пока вы все еще используете его для асинхронного вызова.

Попробуйте удалить оператор using и вместо этого вызвать Dispose в обработчике событий. (Или просто для тестирования, не беспокойтесь об его утилизации.

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

1 голос
/ 07 ноября 2008

Помимо использования чего-то, что, возможно, все еще выполняет асинхронный вызов, о котором упоминали другие люди, я НАСТОЯТЕЛЬНО рекомендую не делать такие вещи в конструкторе формы.

Вместо этого сделайте это в переопределении OnLoad, где вы также сможете проверить свойство DesignMode, которое поможет вам избежать нескольких уровней ада с конструктором форм VS.

1 голос
/ 07 ноября 2008

UNDELETED: Так как многие думают об использовании блока, как я, я подтвердил, что он не связан.

Можете ли вы удалить блок using, я думаю, он ожидает удаления экземпляра webclient.

1 голос
/ 07 ноября 2008

Вы хотите запустить загрузку в другом потоке, см. this в качестве отправной точки.

0 голосов
/ 28 декабря 2016

Эта проблема все еще сохраняется даже в VS2015. Я наконец-то понял, что в коде, который используют люди, нет ничего плохого, проблема в том, насколько быстро вы можете записать данные в элемент управления меткой, и именно это приводит к зависанию процесса и вызывает зависание вашего интерфейса. Попробуйте заменить ваши метки, на которые вы ссылаетесь, текстовыми полями в ваших обработчиках прогрессирования. Это решило все лаги в пользовательском интерфейсе для меня, я надеюсь, что это поможет другим, поскольку я часами пытался выяснить, почему код работает иногда, а не другие.

...