WebClient.DownloadDataAsync замораживает мой пользовательский интерфейс

StackOverflow https://stackoverflow.com/questions/271767

  •  06-07-2019
  •  | 
  •  

Вопрос

У меня есть в моем конструкторе формы после 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 - Программа.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());
        }
    }
}

Форма 1.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;
    }
}
Это было полезно?

Решение

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

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

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

Другие советы

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

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

WebClient webClient = new WebClient();
webClient.Proxy = null;
... Do whatever else ...

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

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

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

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

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

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

ВОССТАНОВЛЕННЫЙ: Поскольку многие думают о блоке using так же, как и я, я подтвердил, что это так не Похожие.

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

DownloadDataAsync противЗагружаемые данные в потоке, отличном от пользовательского интерфейса:

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

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

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

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

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

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

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

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

client.Proxy = GlobalProxySelection.GetEmptyProxy();

По-моему, это выглядит немного странно.

Попробуйте сохранить ссылку на элемент WebClient, чтобы не уничтожать его в конструкторе, возможно, он блокируется на клиенте.Dispose()

Оператор using() пытается вызвать функцию Dispose() веб-клиента, пока он все еще загружается.Метод Dispose, вероятно, ожидает завершения загрузки, прежде чем продолжить.

Попробуйте не использовать инструкцию using() и утилизируйте WebClient в вашем событии DownloadDataCompleted.

Я могу нормально запустить ваш код.И форма появляется, и загрузка завершается ПОСЛЕ того, как форма появилась.

У меня нет никаких зависаний, как вы упомянули.

Я думаю, это как-то связано со средой, в которой вы его запускаете.

На какой версии .NET / Visual Studio вы работаете?

Я попробовал ваш код, и он работает нормально.

Не могли бы вы опубликовать свой основной метод (Args[]) и значения a и b при его запуске:

    int a, b;
    ThreadPool.GetMaxThreads(out a, out b);

Я пробовал это в .NET 3.5 и VS2008.Я в растерянности, но я убежден, что это связано с настройками на вашем компьютере.Не из-за кода.Проверьте эти вещи:

  • Проверьте пул потоков (выше).Я получаю a = 250 b = 1000
  • Отключите все сторонние плагины
  • Загрузка ПРОТИВ "Очистки" (вы перезагрузились)
  • Закройте как можно больше программ / сервисов
  • Проверьте конфигурацию вашего IE.Я думаю, что этот класс использует IE code / settings
  • Брандмауэр?АнтиВирус?
  • Попробуйте это на другом компьютере

Ммм....Мне просто любопытно

У вас включены какие-нибудь брандмауэры?

Любой брандмауэры вообще есть на вашем компьютере?

Может быть, ZoneAlarm?

По моему опыту, это как бы блокирует поток при запуске отладки проекта (запуск его внутри Visual Studio) и при первом обращении к серверу.

При запуске скомпилированного exe-файла блокировка не воспринимается.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top