我在我的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的情况下做到这一点?
感谢您的时间。
最好的问候。
完整代码:
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;
}
}
答案 0 :(得分: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 ...
答案 1 :(得分:4)
现在我们已经有了完整的代码,我可以说我肯定没有看到问题 - 不管怎么说都没有。
我在DownloadDataAsync调用之前和之后以及触发完成的处理程序时都有一些日志记录。如果我通过3G下载大文件,那么 在“之前”和“之后”之间暂停,但是在文件完成下载之前,UI就会出现。
我怀疑 connect 是同步完成的,但实际下载是异步的。当然,这仍然是不幸的 - 并且可能将所有这些都放到一个不同的线程中是要走的路 - 但如果我是对的,至少值得了解。
答案 2 :(得分:1)
您希望在其他主题中运行下载,请参阅this作为起点。
答案 3 :(得分:1)
UNDELETED:正如很多人一样考虑使用块,我已经确认它与无关。
你可以删除使用块,我认为它正在等待处理webclient实例。
答案 4 :(得分:1)
我强烈怀疑,当你仍在使用它进行异步调用时,处理WebClient是有意义的。
尝试删除using语句,然后在事件处理程序中调用Dispose。 (或者仅仅是为了测试,不要担心处理它。
如果您可以发布一个显示问题的short but complete program,那将非常方便。
答案 5 :(得分:1)
除了处理可能仍在运行其他人提到的异步调用的内容之外,我强烈建议不要在表单的构造函数中执行这样的重量级内容。
相反,在OnLoad覆盖中执行此操作,您还可以检查DesignMode属性,这将帮助您避免使用VS表单设计器的几个级别的地狱。
答案 6 :(得分:1)
非UI线程中的DownloadDataAsync与DownloadData:
DownloadDataAsync很不错,因为在请求完成并且服务器响应之后,它在处理DownloadDataCompletedEvent之前实际上并没有占用线程。
我相信Jon Skeet走在正确的轨道上 - 我已经读过DNS解析必须在异步HTTP请求排队并且DownloadDataAsync调用返回之前同步完成。
DNS解析速度是否会变慢?
答案 7 :(得分:1)
我刚刚在VS2010,.NET 4下的WPF项目中测试了同样的东西。
我正在下载带有进度条的文件,以显示使用WebClient.DownloadDataCompleted等完成的百分比。
令我惊讶的是,我发现@Dan提到了同样的事情: 在调试器中,它以一种有趣的方式阻塞线程。在调试中,我的进度表以1%更新,然后暂时不执行任何操作,然后在100%时突然再次更新。 (Debug.WriteLn语句在整个过程中平滑打印)。在这两次之间,UI被冻结了。
但是在调试器之外,进度条平滑地从0%移动到100%,并且UI永远不会冻结。这是你期望的。
答案 8 :(得分:1)
试试这个:
client.Proxy = GlobalProxySelection.GetEmptyProxy();
答案 9 :(得分:0)
我已经尝试过您的代码,但它运行正常。
你可以发布你的Main(Args [])方法以及运行它时a和b的值:
int a, b;
ThreadPool.GetMaxThreads(out a, out b);
我在.NET 3.5和VS2008中尝试过它。我很茫然,但我确信这与你机器上的设置有关。不是代码。检查这些事情:
答案 10 :(得分:0)
这对我来说有点奇怪。
尝试保留WebClient的成员引用,这样你就不会在构造函数中销毁它,也许它在客户端阻塞.Dispose()
答案 11 :(得分:0)
using()语句试图在WebClient仍在下载时调用它的Dispose()。 Dispose方法可能在继续之前等待下载完成。
尽量不要使用using()语句并在DownloadDataCompleted事件中处理WebClient。
答案 12 :(得分:0)
我可以运行你的代码。表格显示后,表格显示后即可完成下载。
我没有像你提到的那样冻结。
我认为它与您在其中运行的环境有关。
您使用的是什么版本的.NET / Visual Studio?
答案 13 :(得分:0)
您有防火墙吗?
您计算机上的所有防火墙?
可能是ZoneAlarm?
答案 14 :(得分:0)
根据我的经验,它在运行调试项目(在Visual Studio中运行)和第一次访问服务器时会阻塞线程。
运行已编译的exe时,阻塞是不可察觉的。
答案 15 :(得分:0)
即使在VS2015中,此问题仍在继续。我终于想通了,人们使用的代码没有任何问题,问题实际上是你可以多快地将数据写入标签控件,这就是挂起过程并导致你的UI冻结的原因。尝试使用progresschanged处理程序中的文本框替换您引用的标签。这为我解决了UI中的所有滞后问题,我希望这可以帮助其他人,因为我花了几个小时试图找出代码为什么有时起作用而不是其他代码。