Aight,做了一些谷歌搜索并在这里搜索,我发现的唯一问题是this,虽然它唯一的答案没有被标记为已被接受,但已经过时且令人困惑。
我的问题基本上就是我在标题中所说的。发生的事情是GUI在上传过程中冻结。我的代码:
// stuff above snipped
public partial class Form1 : Form
{
WebClient wcUploader = new WebClient();
public Form1()
{
InitializeComponent();
wcUploader.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadFileCompletedCallback);
wcUploader.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
}
private void button1_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string toUpload = openFileDialog1.FileName;
wcUploader.UploadFileAsync(new Uri("http://anyhub.net/api/upload"), "POST", toUpload);
}
}
void UploadFileCompletedCallback(object sender, UploadFileCompletedEventArgs e)
{
textBox1.Text = System.Text.Encoding.UTF8.GetString(e.Result);
}
void UploadProgressCallback(object sender, UploadProgressChangedEventArgs e)
{
textBox1.Text = (string)e.UserState + "\n\n"
+ "Uploaded " + e.BytesSent + "/" + e.TotalBytesToSend + "b (" + e.ProgressPercentage + "%)";
}
}
编辑:为了澄清,这是按顺序发生的事情:
答案 0 :(得分:4)
当然可以。
代码工作正常。
wcUploader.UploadFileAsync(...)
启动请求并继续执行,同时在TextBox1中更新进度,完成后我得到一些JSON。
那是异步。如果你只是简单地调用了wcUploader.UploadFile
,那么执行将阻止那里直到文件被上传,你将没有进展事件。
底线:
未阻止UI,调用进度事件并实时更新UI。
更新
要在webclient建立http连接时消除初始阻止,只需在另一个线程上调用上传。在这种情况下,您必须使用调用来防止跨线程异常:
using System;
using System.Net;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private readonly WebClient wcUploader = new WebClient();
public Form1()
{
InitializeComponent();
wcUploader.UploadFileCompleted += UploadFileCompletedCallback;
wcUploader.UploadProgressChanged += UploadProgressCallback;
}
private void UploadFileCompletedCallback(object sender, UploadFileCompletedEventArgs e)
{
// a clever way to handle cross-thread calls and avoid the dreaded
// "Cross-thread operation not valid: Control 'textBox1' accessed
// from a thread other than the thread it was created on." exception
// this will always be called from another thread,
// no need to check for InvokeRequired
BeginInvoke(
new MethodInvoker(() =>
{
textBox1.Text = Encoding.UTF8.GetString(e.Result);
button1.Enabled = true;
}));
}
private void UploadProgressCallback(object sender, UploadProgressChangedEventArgs e)
{
// a clever way to handle cross-thread calls and avoid the dreaded
// "Cross-thread operation not valid: Control 'textBox1' accessed
// from a thread other than the thread it was created on." exception
// this will always be called from another thread,
// no need to check for InvokeRequired
BeginInvoke(
new MethodInvoker(() =>
{
textBox1.Text = (string)e.UserState + "\n\n"
+ "Uploaded " + e.BytesSent + "/" + e.TotalBytesToSend
+ "b (" + e.ProgressPercentage + "%)";
}));
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = "";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
button1.Enabled = false;
string toUpload = openFileDialog1.FileName;
textBox1.Text = "Initiating connection";
new Thread(() =>
wcUploader.UploadFileAsync(new Uri("http://anyhub.net/api/upload"), "POST", toUpload)).Start();
}
}
}
}
答案 1 :(得分:1)
无论UI锁定如何,您的代码中都存在一个值得修复的错误:
指定异步上传器应触发的两个回调。在那些回调中,你将在上传者的线程上运行;但是,您只能从主GUI线程触摸GUI - 因此您的回调可能会破坏GUI的状态。
在任一回调中都不应触及textBox1.Text
。这不太可能是问题,但是,你应该修复它以避免崩溃和腐败错误。您链接的问题说明了避免这种情况的一种方法:检查表单的Control.InvokeRequired
属性(在幕后检查您是否在正确的线程上),或者只是假设需要调用然后 - 使用{ {1}}在GUI线程上触发方法。
您的任何控件都会执行,因为它们都在同一个线程中运行;所以Control.BeginInvoke
和if (textBox1.InvokeRequired) textBox1.BeginInvoke...