Task.WaitAll in a WinForms click handler blocks the window even when the checks themselves use asynchronous HTTP. The UI thread cannot process messages, and captured continuations may need that same blocked thread.

For .NET 6 or later, await a bounded batch instead:

private async void checkButton_Click(object sender, EventArgs e)
{
    checkButton.Enabled = false;
    try
    {
        var entries = proxyList.Lines
            .Where(line => !string.IsNullOrWhiteSpace(line));
        foreach (var batch in entries.Chunk(8))
        {
            var results = await Task.WhenAll(batch.Select(CheckProxyAsync));
            ShowResults(results);
        }
    }
    catch (Exception error)
    {
        ShowCheckError(error);
    }
    finally
    {
        checkButton.Enabled = true;
    }
}

This belongs in an existing form with System.Linq and System.Threading.Tasks available. CheckProxyAsync does bounded asynchronous I/O and returns one result; it does not manipulate controls from a background thread. ShowResults and ShowCheckError are application methods.

The normal await continuation returns to the UI context where the handler began, so ShowResults can update controls. Code explicitly running on another thread must marshal control access through the supported WinForms mechanism.

The free proxy list can supply input addresses; pass only protocols implemented by CheckProxyAsync. Eight is an example budget. The next batch waits for the slowest check in the current batch, trading some throughput for bounded task creation. Keep each check's deadlines and cancellation in CheckProxyAsync; awaiting a batch cannot make an unbounded network operation finish.

Winndannde jowitiiɗe heen