简体   繁体   中英

BeginInvoke is blocking WinForms application

I've created a new WinForms project in Visual Studio 2017. Then I've added a button and textbox to Form1 ( screenshot ).

Code:

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;
            }));
        }
    }
}

When I click button1 window cursor isn't changing to WaitCursor, and when I hover cursor over ControlBox buttons they aren't "glowing". In short, BeginInvoke() blocks main thread for a moment. Why this is happening and how can I avoid it?

As the fellow users said in the comments, it's DownloadString that's blocking your UI, not BeginInvoke since it waits for the download to complete.

You should probably tackle this in another way, by using 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();
}

I second Hans comment : the BeginInvoke only defer execution later.

What you need is either a BackgroundWorker or (better) using the 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;
};

}

The DownloadStringTaskAsync will run on a worker process because it is awaitable. While it runs, the UI thread will continue to process the other events anyway, then continue its execution after the await statement as the DownloadStringTaskAsync finishes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM