【问题标题】:BeginInvoke is blocking WinForms applicationBeginInvoke 正在阻止 WinForms 应用程序
【发布时间】:2018-03-18 15:13:57
【问题描述】:

我在 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://stackoverflow.com/");
                }

                UseWaitCursor = false;
                button1.Enabled = true;
            }));
        }
    }
}

当我单击 button1 时,窗口光标不会变为 WaitCursor,当我将光标悬停在 ControlBox 按钮上时,它们不会“发光”。简而言之,BeginInvoke() 会暂时阻塞主线程。为什么会发生这种情况,我该如何避免?

【问题讨论】:

  • 不,是 DownLoadString() 阻塞了你的 UI。它在 UI 线程上运行。 BeginInvoke() 所做的只是让它在 Click 事件处理程序完成后运行。考虑改用 DownloadStringAsync()。
  • DownloadString() 阻止你而不是BeginInvoke()

标签: c# winforms begininvoke


【解决方案1】:

正如其他用户在 cmets 中所说,是 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://stackoverflow.com/");
}

private void DownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    textBox1.Text = e.Result;
    UseWaitCursor = false;
    button1.Enabled = true;
    _web.Dispose();
}

【讨论】:

  • 这是一个更简单的解决方案,效果很好。但是,了解 async/await 模式是非常有益的。
  • @Larry 这不是异步等待。这是较旧的事件异步模式 (EAP)。 DownloadStringTaskAsync 是 async/await 方法。
【解决方案2】:

我第二个 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://stackoverflow.com/");
    }

    UseWaitCursor = false;
    button1.Enabled = true;
};

}

DownloadStringTaskAsync 将在工作进程上运行,因为它是可等待的。在运行时,UI 线程将继续处理其他事件,然后在等待语句后随着 DownloadStringTaskAsync 完成继续执行。

【讨论】:

  • 这是错误的,DownloadStringAsync 不是任务。见@Scott Chamberlain 评论
  • 糟糕...更新了。
猜你喜欢
  • 1970-01-01
  • 2015-04-21
  • 2020-12-13
  • 2011-10-13
  • 2012-07-12
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
  • 2012-09-03
相关资源
最近更新 更多