0

I have a Winform application that receives the command line arguments and does some processing (creating a file, insert data to the database and upload a file to FTP). So in order to see the process I have a listbox that displays information to the user. There is also a progress bar to see the insert status.

Inside my form load event I have a RunCampaign() function that itself invokes some other functions sequentially until the process is done. All these functions add items to the listbox.

The problem is: Nothing (not even an empty form) is shown until the entire process is done. And when the process is complete the entire form containing the listbox of information and the progress bar is shown. And that is not my expected behavior.

How can I solve this problem?

disasterkid
  • 6,948
  • 25
  • 94
  • 179
  • 1
    Use a BackgroundWorker. Update controls in the ProgressChanged and RunWorkerCompleted events. – LarsTech Aug 19 '14 at 13:41
  • Since you're executing sequentially your logic then either run the logic on Main Thread keeping the ProgressBar on BackgroundWorker or use a Task to run your logic and use main Thread for ProgressBar. – Piyush Aug 19 '14 at 13:44
  • @P.K. Are you saying that it is only the progress bar that is stopping the form to the displayed? Because I just commented out all the code that uses progress bar. – disasterkid Aug 19 '14 at 13:48
  • Minimum that you can do is on `Form_load`, first line should be `Me.Show()`. Than, if you want things to be responsive, use a background worker – T.S. Aug 19 '14 at 16:36
  • @Pedram The form is not being displayed because you are writing your code in Form_Load event. If you write the same code in Form_Shown event instead, your execution will proceed only after the Form is shown to the user. – Piyush Aug 21 '14 at 05:33

2 Answers2

0

You need to multithread your application so your UI thread is free to show the form:

private void Form1_Load(object sender, System.EventArgs e)
{
    Task t = new Task(() =>
    {
        //Logic

        //...

        //Update UI
        this.Invoke((MethodInvoker)delegate
        {
            listbox.Items.Add(...); // runs on UI thread
        });
    });
    t.Start();
}

If you need more examples check out this question: How to update the GUI from another thread in C#?

Community
  • 1
  • 1
Bun
  • 1,465
  • 10
  • 23
  • I have this listbox.Items.Add() function in more than 50 different places in the class. Are you suggesting that I start a new task every time? – disasterkid Aug 19 '14 at 14:07
  • No, it was just an example. Just put all the code in your Form_Load event handler in the task. It will make it run on a different thread. Anytime you want to update the UI, you need to use the `Invoke(...)` call to make sure it is run on the UI thread. Any time a UI element is modified, it needs to be from the UI thread. – Bun Aug 19 '14 at 14:18
  • The thing is, inside my Form1_load() event handler, I have a function called RunCampaign() and this function calls Function2() and Function2() calls Function3() and so on. So there is a sequence of functions that need to be run for the whole process to complete. It is not only one function. Now imagine all of these functions would like to add an item to my listbox. What do you think I should do in this situation? – disasterkid Aug 19 '14 at 14:24
  • @Pedram You will need to break down that method to multiple smaller methods. You cannot run `RunCampaign` on a separate thread and at the same time have it run on the UI thread so it can change the `listbox`... – Bun Aug 19 '14 at 14:28
0

The best way is to use a BackgroundWorker. If you don't want to use any multi-threading technique, then call RunCampaign() function in Form_Shown() event. Also, invoke Listbox.Update() & Progressbar.Update() whenever you modify any item/value. At least you will see the window, but it will not be responsive until the control comes out of Form_Shown().