BeginInvoke 正在阻止 WinForms 应用程序
BeginInvoke is blocking WinForms application
我在 Visual Studio 2017 年创建了一个新的 WinForms 项目。
然后我向 Form1 添加了一个按钮和文本框 (screenshot)。
代码:
using System;
using System.Net;
using System.Windows.Forms;
namespace TestWinForms
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate void FormDelegate();
private void button1_Click(object sender, EventArgs e)
{
UseWaitCursor = true;
button1.Enabled = false;
BeginInvoke(new FormDelegate(delegate
{
using (WebClient web = new WebClient())
{
web.Encoding = System.Text.Encoding.UTF8;
textBox1.Text = web.DownloadString("https://whosebug.com/");
}
UseWaitCursor = false;
button1.Enabled = true;
}));
}
}
}
当我单击按钮 1 时,window 光标没有变为 WaitCursor,当我将光标悬停在 ControlBox 按钮上时,它们也没有变为 "glowing"。简而言之,BeginInvoke()
会暂时阻塞主线程。为什么会发生这种情况,我该如何避免?
正如其他用户在评论中所说,是 DownloadString
阻止了您的 UI,而不是 BeginInvoke
,因为它等待下载完成。
你或许应该用另一种方式解决这个问题,使用 DownloadStringAsync
:
private WebClient _web;
private void button1_Click(object sender, EventArgs e)
{
UseWaitCursor = true;
button1.Enabled = false;
_web = new WebClient();
_web.Encoding = System.Text.Encoding.UTF8;
_web.DownloadStringCompleted += DownloadCompleted;
_web.DownloadStringAsync("https://whosebug.com/");
}
private void DownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
textBox1.Text = e.Result;
UseWaitCursor = false;
button1.Enabled = true;
_web.Dispose();
}
我同意 Hans 的评论:BeginInvoke 只会延迟执行。
您需要的是 BackgroundWorker 或(更好)使用 async/await pattern:
private async void button1_Click(object sender, EventArgs e)
{
UseWaitCursor = true;
button1.Enabled = false;
using (WebClient web = new WebClient())
{
web.Encoding = System.Text.Encoding.UTF8;
textBox1.Text = await web.DownloadStringTaskAsync("https://whosebug.com/");
}
UseWaitCursor = false;
button1.Enabled = true;
};
}
DownloadStringTaskAsync 将 运行 在工作进程上,因为它是可等待的。在 运行s 期间,UI 线程将继续处理其他事件,然后在等待语句之后继续执行 DownloadStringTaskAsync 完成。
我在 Visual Studio 2017 年创建了一个新的 WinForms 项目。 然后我向 Form1 添加了一个按钮和文本框 (screenshot)。
代码:
using System;
using System.Net;
using System.Windows.Forms;
namespace TestWinForms
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate void FormDelegate();
private void button1_Click(object sender, EventArgs e)
{
UseWaitCursor = true;
button1.Enabled = false;
BeginInvoke(new FormDelegate(delegate
{
using (WebClient web = new WebClient())
{
web.Encoding = System.Text.Encoding.UTF8;
textBox1.Text = web.DownloadString("https://whosebug.com/");
}
UseWaitCursor = false;
button1.Enabled = true;
}));
}
}
}
当我单击按钮 1 时,window 光标没有变为 WaitCursor,当我将光标悬停在 ControlBox 按钮上时,它们也没有变为 "glowing"。简而言之,BeginInvoke()
会暂时阻塞主线程。为什么会发生这种情况,我该如何避免?
正如其他用户在评论中所说,是 DownloadString
阻止了您的 UI,而不是 BeginInvoke
,因为它等待下载完成。
你或许应该用另一种方式解决这个问题,使用 DownloadStringAsync
:
private WebClient _web;
private void button1_Click(object sender, EventArgs e)
{
UseWaitCursor = true;
button1.Enabled = false;
_web = new WebClient();
_web.Encoding = System.Text.Encoding.UTF8;
_web.DownloadStringCompleted += DownloadCompleted;
_web.DownloadStringAsync("https://whosebug.com/");
}
private void DownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
textBox1.Text = e.Result;
UseWaitCursor = false;
button1.Enabled = true;
_web.Dispose();
}
我同意 Hans 的评论:BeginInvoke 只会延迟执行。
您需要的是 BackgroundWorker 或(更好)使用 async/await pattern:
private async void button1_Click(object sender, EventArgs e)
{
UseWaitCursor = true;
button1.Enabled = false;
using (WebClient web = new WebClient())
{
web.Encoding = System.Text.Encoding.UTF8;
textBox1.Text = await web.DownloadStringTaskAsync("https://whosebug.com/");
}
UseWaitCursor = false;
button1.Enabled = true;
};
}
DownloadStringTaskAsync 将 运行 在工作进程上,因为它是可等待的。在 运行s 期间,UI 线程将继续处理其他事件,然后在等待语句之后继续执行 DownloadStringTaskAsync 完成。