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