6

私は、InitializeComponent の後に次のコードを Form コンストラクターに持っています。

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

フォームを開始すると、client_DownloadDataCompleted が発生するまで UI が表示されません。client_DownloadDataCompleted メソッドは空なので問題ありません。

私が間違っていることは何ですか?UIをフリーズせずにこれを行うにはどうすればよいですか?

御時間ありがとうございます。
よろしくお願いします。

完全なコード:

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;
    }
}
4

16 に答える 16

5

完全なコードを取得したので、問題はまったく見られないと言えます。とにかく、説明したとおりではありません。

DownloadDataAsync 呼び出しの直前と直後、および完了したハンドラーがいつ起動されるかを示すために、少しログを記録しました。3G 経由で大きなファイルをダウンロードすると、「前」と「後」の間に一時停止がありますが、ファイルのダウンロードが完了する前に UI が表示されます。

接続は同期的に行われているのではないかと疑っていますが、実際のダウンロードは非同期です。もちろん、それはまだ残念です-そして、おそらくそれらすべてを別のスレッドにパントするのが道です-しかし、私が正しければ、少なくとも知る価値があります.

于 2008-11-07T12:32:23.480 に答える
1

他の人が言及している非同期呼び出しをまだ実行している可能性のあるものを破棄するだけでなく、フォームのコンストラクターでこのような重いものを実行しないことを強くお勧めします。

代わりに、OnLoadオーバーライドで実行してください。この場合、DesignModeプロパティを確認することもできます。これは、VSフォームデザイナでいくつかのレベルの地獄を回避するのに役立ちます。

于 2008-11-07T11:28:02.797 に答える
1

VS2010、.NET 4 の WPF プロジェクトで同じことをテストしました。

WebClient.DownloadDataCompleted などを使用して完了したパーセンテージを表示する進行状況バーを含むファイルをダウンロードしています。

そして、驚いたことに、@Dan が言及したのと同じことを見つけています。デバッガー内では、面白い方法でスレッドをブロックします。デバッグでは、進行状況メーターが 1% で更新され、しばらく何もしませんでしたが、突然 100% で再び更新されます。(Debug.WriteLn ステートメントは全体を通してスムーズに出力されます)。この 2 回の間、UI はフリーズします。

ただし、デバッガーの外では、進行状況バーが 0% から 100% までスムーズに移動し、UI がフリーズすることはありません。これはあなたが期待するものです。

于 2010-05-19T21:37:43.470 に答える
1

非 UI スレッドでの DownloadDataAsync と DownloadData の比較:

DownloadDataAsync は、要求が行われてサーバーが応答した後、DownloadDataCompletedEvent を処理するまで実際にスレッドを結び付けないため、優れています。

Jon Skeet は正しい方向に進んでいると思います。非同期 HTTP 要求がキューに入れられ、DownloadDataAsync 呼び出しが返される前に、DNS 解決が同期的に完了する必要があることを読みました。

DNS 解決が遅い可能性はありますか?

于 2008-11-26T21:48:17.510 に答える
1

この問題は、VS2015 でもまだ進行中です。私はついにこれを理解しました。人々が使用しているコードに問題はありません。問題は、実際にはラベル コントロールにデータを書き込む速度であり、これがプロセスをハングアップさせ、UI をフリーズさせます。参照するラベルを、progresschanged ハンドラーのテキスト ボックスに置き換えてみてください。これにより、UI のすべての遅延が解決されました。コードが機能する理由と他の機能が機能しない理由を理解するのに何時間も費やしたので、これが他の人に役立つことを願っています.

于 2016-12-27T21:17:20.113 に答える
1

非同期呼び出しにまだ使用している間に WebClient を破棄することに関係していると強く思います。

using ステートメントを削除してみて、代わりにイベント ハンドラーで Dispose を呼び出してください。(または、テストのためだけに、破棄することをまったく心配しないでください。

問題を示す短いが完全なプログラムを投稿できれば、それは非常に便利です。

于 2008-11-07T11:24:20.840 に答える
1

これを試して:

client.Proxy = GlobalProxySelection.GetEmptyProxy();
于 2011-04-04T20:58:50.583 に答える
1

ダウンロードを別のスレッドで実行したい場合は、これを開始点として参照してください。

于 2008-11-07T11:04:57.540 に答える
1

UNDELETED:多くの人が私と同じように using ブロックについて考えているので、関連していないことを確認しました。

using ブロックを削除できますか。webclient インスタンスの破棄を待っていると思います。

于 2008-11-07T11:15:33.273 に答える
0

私はあなたのコードをうまく実行することができます。そして、フォームが表示され、フォームが表示された後にダウンロードが完了します。

おっしゃるようにフリーズはありません。

それはあなたがそれを実行している環境と関係があると思います。

どのバージョンの.NET/Visual Studioを使用していますか?

于 2008-11-07T11:38:24.353 に答える
0

うーん....私はただ興味があります

ファイアウォールをオンにしていますか?

マシンにファイアウォールはありますか

多分ZoneAlarm?

于 2008-11-07T11:52:24.403 に答える
0

using()ステートメントは、ダウンロード中にWebClientのDispose()を呼び出そうとしています。Disposeメソッドは、ダウンロードが完了するのを待ってから続行します。

using()ステートメントを使用せず、DownloadDataCompletedイベントでWebClientを破棄してください。

于 2008-11-07T11:27:11.927 に答える
0

私の経験では、プロジェクトのデバッグを実行するとき (Visual Studio 内で実行するとき)、およびサーバーに初めてアクセスするときに、スレッドをブロックします。

コンパイルされた exe を実行すると、ブロックは認識できません。

于 2009-11-07T20:43:20.990 に答える
0

私はあなたのコードを試してみましたが、うまくいきます。

Main(Args[]) メソッドと、これを実行したときの a と b の値を投稿していただけますか。

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

.NET 3.5 と VS2008 で試しました。私は途方に暮れていますが、それはあなたのマシンのセットアップに関係していると確信しています. コードではありません。次のことを確認してください。

  • スレッド プールを確認します (上記)。a=250 b=1000 を得ます
  • サードパーティのプラグインをすべて無効にする
  • Load VS "Clean" (再起動しましたか)
  • できるだけ多くのプログラム/サービスを閉じます
  • IE の設定を確認してください。クラスはIEコード/設定を使用していると思います
  • ファイアウォール?アンチウイルス?
  • 別のコンピューターで試す
于 2008-11-07T11:12:52.937 に答える
0

それは私には少し奇妙に見えます。

コンストラクターで破棄しないように、WebClient のメンバー ref を保持してみてください。おそらく client.Dispose() でブロックされている可能性があります。

于 2008-11-07T11:13:27.100 に答える