6

我在我的 Form 构造函数中,在 InitializeComponent 之后有以下代码:

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

当我启动我的表单时,UI 直到 client_DownloadDataCompleted 被提出后才会出现。client_DownloadDataCompleted 方法是空的,所以那里没有问题。

我做错了什么?在不冻结 UI 的情况下应该如何做到这一点?

谢谢你的时间。
最好的祝福。

完整代码:

程序.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 下载一个大文件,“之前”和“之后”之间会有一个暂停,但用户界面会在文件完成下载之前出现很长时间。

我怀疑连接是同步完成的,但实际下载是异步的。当然,这仍然很不幸 - 可能将所有这些都放到不同的线程中是要走的路 - 但如果我是对的,至少值得了解。

于 2008-11-07T12:32:23.480 回答
5

遇到了同样的问题,找到了解决办法。这里相当复杂的讨论: http ://social.msdn.microsoft.com/Forums/en-US/a00dba00-5432-450b-9904-9d343c11888d/webclient-downloadstringasync-freeze-my-ui?forum=ncl

简而言之,问题在于 Web 客户端正在搜索代理服务器并挂起应用程序。以下解决方案有帮助:

WebClient webClient = new WebClient();
webClient.Proxy = null;
... Do whatever else ...
于 2014-04-05T20:52:21.220 回答
1

您想在不同的线程中运行下载,请将此视为起点。

于 2008-11-07T11:04:57.540 回答
1

未删除:许多人像我一样考虑使用块,我已经确认它相关。

您可以删除 using 块吗,我认为它正在等待处置 webclient 实例。

于 2008-11-07T11:15:33.273 回答
1

我强烈怀疑这与在您仍在使用 WebClient 进行异步调用时处理它有关。

尝试删除 using 语句,并改为在事件处理程序中调用 Dispose。(或者只是为了测试,根本不用担心处理它。

如果您可以发布一个简短但完整的程序来演示该问题,那将非常方便。

于 2008-11-07T11:24:20.840 回答
1

除了处理其他人提到的可能仍在运行异步调用的东西之外,我强烈建议不要在表单的构造函数中做这样的重量级事情。

而是在 OnLoad 覆盖中执行此操作,您还可以在其中检查 DesignMode 属性,这将帮助您避免 VS 表单设计器的多个级别的地狱。

于 2008-11-07T11:28:02.797 回答
1

非 UI 线程中的 DownloadDataAsync 与 DownloadData:

DownloadDataAsync 很好,因为它在处理 DownloadDataCompletedEvent 之前实际上并没有占用线程,在请求发出并且服务器响应之后。

我相信 Jon Skeet 走在正确的轨道上 - 我已经读过 DNS 解析必须在异步 HTTP 请求排队并且 DownloadDataAsync 调用返回之前同步完成。

DNS解析会慢吗?

于 2008-11-26T21:48:17.510 回答
1

我刚刚在 VS2010、.NET 4 下的 WPF 项目中测试了同样的东西。

我正在下载一个带有进度条的文件,以显示使用 WebClient.DownloadDataCompleted 等完成的百分比。

而且,令我惊讶的是,我发现@Dan 提到的同样的事情:在调试器中,它以一种有趣的方式阻塞了线程。在调试中,我的进度表以 1% 的速度更新,然后有一段时间什么也不做,然后又突然以 100% 的速度更新。(Debug.WriteLn 语句自始至终都能顺利打印)。在这两次之间,UI 被冻结。

但是在调试器之外,进度条从 0% 到 100% 平滑移动,并且 UI 永远不会冻结。这是你所期望的。

于 2010-05-19T21:37:43.470 回答
1

试试这个:

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

即使在 VS2015 中,这个问题仍然存在。我终于弄清楚了,人们使用的代码没有任何问题,问题实际上是你可以多快将数据写入标签控件,这就是挂起进程并导致 UI 冻结的原因。尝试将您引用的标签替换为您的 progresschanged 处理程序中的文本框。这为我解决了 UI 中的所有滞后问题,我希望这对其他人有所帮助,因为我花了数小时试图弄清楚为什么代码有时会起作用而不是其他代码。

于 2016-12-27T21:17:20.113 回答
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 的成员引用,这样您就不会在构造函数中销毁它,也许它在 client.Dispose() 上阻塞

于 2008-11-07T11:13:27.100 回答
0

using() 语句试图在 WebClient 仍在下载时调用 Dispose()。Dispose 方法可能会在继续之前等待下载完成。

尝试不使用 using() 语句并在 DownloadDataCompleted 事件中处理 WebClient。

于 2008-11-07T11:27:11.927 回答
0

我可以很好地运行你的代码。表格出现并在表格出现后完成下载。

正如你所说,我没有任何冻结。

我认为这与您在其中运行它的环境有关。

您使用的是哪个版本的 .NET/Visual Studio?

于 2008-11-07T11:38:24.353 回答
0

嗯....我只是好奇

你有防火墙吗?

你的机器上有防火墙吗?

也许ZoneAlarm?

于 2008-11-07T11:52:24.403 回答
0

根据我的经验,它在运行调试项目(在 Visual Studio 中运行)和第一次访问服务器时会阻塞线程。

运行已编译的 exe 时,无法感知阻塞。

于 2009-11-07T20:43:20.990 回答