How to refactor code to use threads?
I would not show any UI from WebPostRequest. For a fast solution you can just wrap the whole upload part and provide some sort of a listener whose methods will be called to notify about progress.

Thus WebPostRequest will not know nothing about UI layer. UI will not be blocked and be able to track upload progress.

Here's a C#-like pseudo code that illustrates what I mean:

class ProgressListener
{
    public void OnProgress(OperationContext)
    {
        //notiy UI in the thread-safe way -&gt; use Control.Invoke for Windows Forms
    }

    public void OnFinish(OperationContext)
    {
        //show success message in UI
    }

    public void OnError(OperationContext)
    {
        //show detailed error message in UI
    }
}

//on UI class
void PerformUpload()
{

    ProgressListener listener = new ProgressListener(Form f);

    Thread thread = new Thread(() =&gt;
    {
        try
        {
            try
            {
                WebPostRequest webPostRequest = new WebPostRequest(url);
                webPostRequest.Add("key_1", "value_1");
                webPostRequest.Add("key_2", "value_2");

                webPostRequest.UploadPdf("key_3", "pdf_name_1", userControl1);

                listener.OnProgress( /*operaton context*/)

                webPostRequest.UploadPdf("key_4", "pdf_name_2", userControl2);

                listener.OnProgress( /*operaton context*/)
                webPostRequest.UploadImage("key_5", "picture_name_1", image1);

                listener.OnProgress( /*operaton context*/)
                webPostRequest.UploadImage("key_6", "picture_name_1", image2);

                listener.OnProgress( /*operaton context*/)

                string response = webPostRequest.GetResponse();
                if (response != WebPostRequest.Success)
                {
                    listener.OnProgress( /*operaton context*/)

                    throw new Exception(response);
                }
                success = true;

                listener.OnFinish( /*operaton context*/)
            }
            catch (Exception ex)
            {
                listener.OnError( /*operaton context*/)
                //display error messaage
            }       
        }
        catch(Exception ex)
        {
            listener.OnError( /*operaton context*/)
            //logging
        }
    });

    thread.Name = "uploader";
    thread.Start();
}