Creating multiple threads to process items in a listview
We actually don't use the BackgroundWorker anymore. The same thing can be done much easier with the newer Task Parallel Library (TPL).



Briefly you need to (ok, you should) put the download logic into a new class that could have a Download method. It needs to be marked with async and return a Task to be awaitable. But you need a result so you can use it with a generic parameter Task&lt;byte[]&gt;. (Sidenote: remember to dispose the WebClient). For the new download to work you need to use the awaitable upload API. 

If you want to be able to report progress or just be notified when a task is finished you can use the IProgress&lt;T&gt; interface as one of the parameters. You call it inside the method to report its progress. Here just an arbitrary task-id. 

class Downloader
{
    public async Task&lt;byte[]&gt; Download(int taskId, NameValueCollection data, IProgress&lt;int&gt; progress)
    {
        using (var client = new WebClient())
        {
            var response = await client.UploadValuesTaskAsync("http://google.com", data);
            progress.Report(taskId);
            return response;
        }
    }
}


Your form code could then be reduced to a simple event handler that is also marked with async. It prepares a collection of download-tasks and then awaits them all or processes each one when it's finished (your choice).

When a task is finished, the form receives a progress report (that can be seen here as a notification) via the ProgressChanged event of an instance of the Progress&lt;T&gt; class.

class MyForm : Form
{
    private readonly Downloader _downloader = new Downloader();

    private async void button2_Click(object sender, EventArgs e)
    {
        // Initialize progress handling.
        var progress = new Progress&lt;int&gt;();
        progress.ProgressChanged += (downloader, taskId) =&gt; 
        {
            // update label...
        };

        var downloadCount = 2; //... get the count
        var downloadTasks = 
            Enumerable
            .Range(0, downloadCount)
            // Create task specific arguments.
            .Select((x, i) =&gt; _downloader.Download(i, new NameValueCollection(), progress));

        var results = await Task.WhenAll(downloadTasks);
    }
}




You may also use a different pattern if you want to process each task result right away by doing it as soon as any task is finished with WhenAny and a loop:

for (int i = 0; i &lt; downloadCount; i++)
{
    var firstTask = await Task.WhenAny(downloadTasks);
    var result = await firstTask;
    // process task result...
}