Question

J'ai dans mon constructeur de formulaire, après le code InitializeComponent:

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

Lorsque je commence mon formulaire, l'interface utilisateur n'apparaît que lorsque client_DownloadDataCompleted est généré. La méthode client_DownloadDataCompleted est vide, il n'y a donc aucun problème là-bas.

Qu'est-ce que je fais mal? Comment est-il supposé faire cela sans geler l'interface utilisateur?

Merci pour votre temps.
Cordialement.

CODE COMPLET:

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;
    }
}
Était-ce utile?

La solution

Maintenant que nous avons le code complet, je peux dire que je ne vois absolument pas le problème - pas tout à fait comme décrit, de toute façon.

J'ai un peu de journalisation à indiquer juste avant et après les appels DownloadDataAsync, et lorsque le gestionnaire terminé est déclenché. Si je télécharge un fichier volumineux en 3G, il y a une pause entre "avant" et "avant". et " après " mais l'interface utilisateur est longue avant que le téléchargement du fichier ne soit terminé.

Je soupçonne que la connexion est effectuée de manière synchrone, mais le téléchargement réel est asynchrone. C’est toujours malheureux, bien sûr, et il est peut-être judicieux de faire tout cela dans une autre direction, mais si je ne me trompe pas, il vaut au moins la peine de le savoir.

Autres conseils

Nous avons rencontré le même problème et trouvé une solution. Discussion assez complexe ici: http://social.msdn.microsoft.com/Forums/en-US/a00dba00-5432-450b-9904-9d343c11888d/webclient-downloadstringasync-freeze-my-ui?forum=ncl

En bref, le problème est que le client Web recherche des serveurs proxy et suspend l'application. La solution suivante aide:

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

Vous souhaitez exécuter le téléchargement dans un autre thread, voir ceci comme point de départ.

Je suspecte fortement qu'il s'agisse de la suppression du Web Client alors que vous l'utilisez encore pour un appel asynchrone.

Essayez de supprimer l'instruction using et appelez plutôt Dispose dans un gestionnaire d'événements. (Ou juste pour les tests, ne vous inquiétez pas du tout.

Si vous pouviez publier un programme bref mais complet qui illustre le problème, ce serait vraiment pratique.

En plus de la suppression de quelque chose qui exécute peut-être encore l'appel asynchrone mentionné par d'autres personnes, je recommanderais FORTEMENT de ne pas faire de choses lourdes comme celle-ci dans le constructeur d'un formulaire.

Faites-le plutôt dans une substitution OnLoad, où vous pourrez également vérifier la propriété DesignMode, ce qui vous aidera à éviter plusieurs niveaux d'enfer avec le concepteur de formulaires VS.

UNDELETED: Comme beaucoup de personnes pensent au bloc using comme moi, j'ai confirmé qu'il n'est pas lié.

Pouvez-vous supprimer le bloc using, je pense qu'il attend de disposer de l'instance WebClient.

DownloadDataAsync vs DownloadData dans un thread non-UI:

DownloadDataAsync est pratique, car elle n'attache pas de fil jusqu'à la gestion de DownloadDataCompletedEvent, après que la demande a été effectuée et que le serveur a répondu.

Je pense que Jon Skeet est sur la bonne voie. J'ai lu que la résolution DNS doit se terminer de manière synchrone avant que la requête HTTP asynchrone ne soit mise en file d'attente et que l'appel DownloadDataAsync ne soit renvoyé.

La résolution DNS peut-elle être lente?

Je viens de tester la même chose dans un projet WPF sous VS2010, .NET 4.

Je télécharge un fichier avec une barre de progression pour afficher le pourcentage terminé à l'aide de WebClient.DownloadDataCompleted, etc.

Et, à mon grand étonnement, je trouve la même chose que @Dan a mentionnée: Dans le débogueur, il bloque le fil de manière amusante. En débogage, mon indicateur de progression est mis à jour à 1%, puis ne fait rien pendant un moment, puis se met à nouveau à jour à 100%. (Les instructions Debug.WriteLn s’impriment sans à-coups). Et entre ces deux moments, l'interface utilisateur est gelée.

Mais en dehors du débogueur, la barre de progression se déplace sans à-coups de 0% à 100% et l'interface utilisateur ne se fige jamais. Quel est ce que vous attendez.

essayez ceci:

client.Proxy = GlobalProxySelection.GetEmptyProxy();

Cela me semble un peu bizarre.

Essayez de garder un membre ref du Web Client afin de ne pas le détruire dans le constructeur, il bloquera peut-être sur le client.Dispose ()

L'instruction using () essaie d'appeler Dispose () du Web Client en cours de téléchargement. La méthode Dispose attend probablement la fin du téléchargement avant de continuer.

Essayez de ne pas utiliser d'instruction using () et de supprimer le WebClient dans votre événement DownloadDataCompleted.

Je peux exécuter votre code correctement. Et le formulaire apparaît et le téléchargement est terminé APRÈS que le formulaire soit affiché.

Je n'ai aucun gel, comme vous l'avez mentionné.

Je pense que cela a quelque chose à voir avec l'environnement dans lequel vous l'exécutez.

Sur quelle version de .NET / Visual Studio êtes-vous?

J'ai essayé votre code et cela fonctionne bien.

Pourriez-vous publier votre méthode Main (Args []) et la valeur de a et b lorsqu'elle est exécutée:

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

Je l'ai essayé dans .NET 3.5 et VS2008. Je suis perdu, mais je suis convaincu que cela a à voir avec l'installation de votre machine. Pas le code. Vérifiez ces choses:

  • Vérifiez le pool de threads (ci-dessus). Je reçois a = 250 b = 1000
  • Désactiver tous les plugins tiers
  • Charger VS " Nettoyer " (Avez-vous redémarré)
  • Fermez autant de programmes / services que vous le pouvez
  • Vérifiez votre configuration IE. Je pense que cette classe utilise le code IE / les paramètres
  • Pare-feu? AntiVirus?
  • Essayez-le sur un autre ordinateur

Ummm .... je suis juste curieux

Avez-vous des pare-feu?

des pare-feu du tout sur votre machine?

Peut-être ZoneAlarm?

D'après mon expérience, cela bloque le thread lors de l'exécution du débogage du projet (exécution dans Visual Studio) et lors de la première utilisation du serveur.

Lors de l'exécution de l'exe compilé, le blocage n'est pas perceptible.

Ce problème est toujours d'actualité, même dans VS2015. J'ai finalement compris que le code utilisé par les utilisateurs était sans faille. Le problème est en fait de savoir à quelle vitesse vous pouvez écrire des données dans un contrôle d'étiquette. C'est ce qui bloque le processus et provoque le blocage de votre interface utilisateur. Essayez de remplacer les étiquettes que vous avez référencées par des zones de texte dans vos gestionnaires de changement progressif. Pour moi, cela a résolu tous les problèmes d'interface utilisateur. J'espère que cela aidera les autres, car j'ai passé des heures à essayer de comprendre pourquoi le code fonctionnait parfois et non d'autres.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top