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 完成。