Domanda

Ho nel mio costruttore Form, dopo InitializeComponent il seguente codice:

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

Quando avvio il mio modulo, l'interfaccia utente non viene visualizzata finché non viene sollevato client_DownloadDataCompleted. Il metodo client_DownloadDataCompleted è vuoto, quindi non ci sono problemi.

Cosa sto facendo di sbagliato? Come dovrebbe farlo senza congelare l'interfaccia utente?

Grazie per il tuo tempo.
Cordiali saluti.

CODICE COMPLETO:

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;
    }
}
È stato utile?

Soluzione

Ora che abbiamo il codice completo, posso dire che sicuramente non vedo il problema, comunque non esattamente come descritto.

Ho un po 'di registrazione da indicare poco prima e dopo le chiamate DownloadDataAsync e quando viene attivato il gestore completo. Se scarico un file di grandi dimensioni tramite 3G, è una pausa tra " prima di " e "dopo" ma l'interfaccia utente arriva prima che il download del file venga completato.

Ho il sospetto che il connetti sia fatto in modo sincrono, ma il download effettivo è asincrono. Questo è ancora sfortunato, ovviamente - e forse aggiungere tutto in un thread diverso è la strada da percorrere - ma se ho ragione vale la pena sapere almeno.

Altri suggerimenti

Si è verificato lo stesso problema e trovato una soluzione. Discussione abbastanza complessa qui: http://social.msdn.microsoft.com/Forums/en-US/a00dba00-5432-450b-9904-9d343c11888d/webclient-downloadstringasync-freeze-my-ui?forum=ncl

In breve, il problema è che il client Web sta cercando server proxy e sta appendendo l'app. La seguente soluzione aiuta:

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

Desideri eseguire il download in un thread diverso, vedi questo come punto di partenza.

Sospetto fortemente che abbia a che fare con lo smaltimento di WebClient mentre lo stai ancora utilizzando per una chiamata asincrona.

Prova a rimuovere l'istruzione using e chiama invece Dispose in un gestore eventi. (O solo per i test, non preoccuparti di smaltirlo affatto.

Se potessi pubblicare un programma breve ma completo che dimostra il problema, sarebbe davvero utile.

Oltre allo smaltimento di qualcosa che probabilmente sta ancora eseguendo la chiamata asincrona che è stata menzionata da altre persone, raccomanderei VIVAMENTE di fare cose pesanti come questa nel costruttore di un modulo.

Fallo invece con una sostituzione OnLoad, dove potrai anche controllare la proprietà DesignMode che ti aiuterà a evitare diversi livelli infernali con il progettista di moduli VS.

UNDELETED: Come molti pensano all'utilizzo del blocco come me, ho confermato che non è non correlato.

Riesci a rimuovere il blocco using, penso che sia in attesa di disporre l'istanza webclient.

DownloadDataAsync vs. DownloadData in un thread non UI:

DownloadDataAsync è utile perché in realtà non collega un thread fino alla gestione di DownloadDataCompletedEvent, dopo che la richiesta è stata effettuata e il server risponde.

Credo che Jon Skeet sia sulla buona strada: ho letto che la risoluzione DNS deve essere completata in modo sincrono prima che la richiesta HTTP asincrona venga messa in coda e la chiamata DownloadDataAsync ritorni.

La risoluzione DNS potrebbe essere lenta?

Ho appena testato la stessa cosa in un progetto WPF sotto VS2010, .NET 4.

Sto scaricando un file con una barra di avanzamento per mostrare la percentuale completata utilizzando WebClient.DownloadDataCompleted ecc.

E, con mio grande stupore, sto trovando la stessa cosa che @Dan ha menzionato: All'interno del debugger blocca il thread in modo divertente. Nel debug, il mio indicatore di progresso viene aggiornato all'1%, quindi non fa nulla per un po ', quindi si aggiorna improvvisamente al 100%. (Le istruzioni Debug.WriteLn vengono stampate senza problemi). E tra queste due volte, l'interfaccia utente è bloccata.

Ma al di fuori del debugger, la barra di avanzamento si sposta agevolmente dallo 0% al 100% e l'interfaccia utente non si blocca mai. È quello che ti aspetteresti.

prova questo:

client.Proxy = GlobalProxySelection.GetEmptyProxy();

Mi sembra un po 'strano.

Prova a mantenere un riferimento membro del WebClient in modo da non distruggerlo nel costruttore, forse si sta bloccando sul client.Dispose ()

L'istruzione using () sta provando a chiamare Dispose () di WebClient mentre sta ancora scaricando. Il metodo Dispose probabilmente attende il completamento del download prima di continuare.

Prova a non utilizzare un'istruzione using () e elimina WebClient nell'evento DownloadDataCompleted.

Posso eseguire bene il tuo codice. E il modulo viene visualizzato e il download è completato DOPO il modulo visualizzato.

Non ho alcun blocco come hai menzionato.

Penso che abbia qualcosa a che fare con l'ambiente in cui lo stai eseguendo.

Su quale versione di .NET / Visual Studio sei in uso?

Ho provato il tuo codice e funziona benissimo.

Potresti pubblicare il tuo metodo Main (Args []) e il valore di aeb quando viene eseguito:

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

L'ho provato in .NET 3.5 e VS2008. Sono in perdita, ma sono convinto che abbia a che fare con l'installazione sulla tua macchina. Non il codice. Controlla queste cose:

  • Controlla il pool di thread (sopra). Ottengo a = 250 b = 1000
  • Disabilita tutti i plugin di terze parti
  • Carica VS " Clean " (Hai riavviato)
  • Chiudi quanti più programmi / servizi puoi
  • Controlla la tua configurazione IE. Penso che la classe usi il codice / impostazioni IE
  • Firewall? AntiVirus?
  • Provalo su un altro computer

Ummm .... sono solo curioso

Hai qualche firewall attivato?

qualsiasi firewall sulla tua macchina?

Forse ZoneAlarm?

Nella mia esperienza, blocca il thread durante l'esecuzione del debug del progetto (eseguendolo all'interno di Visual Studio) e quando si accede al server per la prima volta.

Quando si esegue l'exe compilato, il blocco non è percepibile.

Questo problema è ancora in corso anche in VS2015. Alla fine l'ho capito, non c'è niente di sbagliato nel codice che le persone usano, il problema è in realtà la velocità con cui puoi scrivere i dati su un controllo etichetta e questo è ciò che blocca il processo e causa il blocco della tua interfaccia utente. Prova a sostituire le etichette a cui fai riferimento con le caselle di testo nei gestori modificati progressivamente. Ciò ha risolto tutti i ritardi nell'interfaccia utente per me, spero che questo aiuti gli altri mentre passavo ore a cercare di capire perché il codice funzionava a volte e non altri.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top