2

I want to display an animated loading form while executing some code in the main form. The animated form is used only to show the user that an operation is executing and I want to close it once the operation finishes. The code that I'm using is:

    public partial class Form_main_admin : Form
    {
        private Thread loadingThread;
        private string loadingText;

        public Form_main_admin()
        {
            InitializeComponent();
        }

     private void main_tabControl_SelectedIndexChanged(object sender, EventArgs e)
     { 
         switch (main_tabControl.SelectedIndex)
         {
             case 0:
                 // ...
                 break;
             case 1:
                 showLoadingForm("Loading");

                 // Load a datagridview (load data, adjust column widths) in Form_main_admin

                 closeLoadingForm();
                 break;
            }
    }

    private void showLoadingForm(string text)
    {
         loadingText = text;
         loadingThread = new Thread(new ThreadStart(openLoadingForm));
         loadingThread.Start();
    }

    private void openLoadingForm()
    {
         try
         {
             Form_loading loadingForm = new Form_loading(loadingText);
             loadingForm.ShowDialog();
         }
         catch 
         {
             Thread.ResetAbort();
         }
     }

     private void closeLoadingForm()
     {
         try
         {
             loadingThread.Abort();
         }
         catch 
         {
             Thread.ResetAbort();
         }

     }
}

The problem is that I get a "Thread was being aborted" exception when I quickly change between tabs (see image in link below).

http://postimg.org/image/bvre2bmi5/

I do not want the user to see this exception if he chages tabs too fast. After reading other posts on this forum I realized that my implementation is not recommended. Could someone please show me how to properly implement this functionality?

Cristian M
  • 715
  • 2
  • 12
  • 32
  • The basic principle is to update the HMI only in main thread and to run additional threads for "background" tasks. Then, you should first load the DataGridView source in a secondary thread, display your animated form on the main thread. Then, when data loading is completed, assign this data to datagidview and close the animated form. – Graffito Jul 09 '15 at 11:21
  • instead of animation you can just ser mouse cursor to indicate that there is ome work being done. have a look here http://stackoverflow.com/questions/1568557/how-can-i-make-the-cursor-turn-to-the-wait-cursor – vidriduch Jul 09 '15 at 11:22
  • This is a pretty standard bug, it has *very* nasty consequences that can crash your program long after the "loading form" is closed. Very hard to debug, looks [like this](http://blogs.msdn.com/b/dsui_team/archive/2012/10/31/debugging-windows-forms-application-hangs-during-systemevents.userpreferencechanged.aspx). You **must** do it the other way around, display the loading form on the UI thread and execute the slow code on the worker thread. BackgroundWorker makes it simple. – Hans Passant Jul 09 '15 at 11:26
  • Maybe try `using (Form_loading loadingForm = new Form_loading(loadingText)) { loadingForm.ShowDialog(); //Your data loading code here loadingForm.Close(); }` But I don't recommend this solution. Better just use waiting mouse cursor or simply add a progress bar in middle of your tab page. – Nam Bình Jul 09 '15 at 11:27
  • @Graffito Thank you for explaining the correct implementation principle. vidriduch, thanks for your suggestion. I have forgotten that I can use the mouse to show loading activities. I will change the cursor, because the implementation is simpler and the functionality is the same. – Cristian M Jul 09 '15 at 12:01

1 Answers1

1

If you need an animated progress form, try to use BackgroundWorker class to perform loading in an additional thread:

    public partial class MainForm : Form
    {
        /// <summary>
        /// Some progress form
        /// </summary>
        WaitForm waitForm = new WaitForm();

        /// <summary>
        /// https://msdn.microsoft.com/library/cc221403(v=vs.95).aspx
        /// </summary>
        BackgroundWorker worker = new BackgroundWorker();

        public MainForm()
        {
            InitializeComponent();

            worker.DoWork += (sender, args) => PerformReading();
            worker.RunWorkerCompleted += (sender, args) => ReadingCompleted();
        }

        /// <summary>
        /// This method will be executed in an additional thread
        /// </summary>
        void PerformReading()
        {
            //some long operation here
            Thread.Sleep(5000);
        }

        /// <summary>
        /// This method will be executed in a main thread after BackgroundWorker has finished
        /// </summary>
        void ReadingCompleted()
        {                        
           waitForm.Close();
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            //Run reading in an additional thread
            worker.RunWorkerAsync();
            //Show progress form in a main thread
            waitForm.ShowDialog();
        }
    }
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Igor Bendrup
  • 2,637
  • 2
  • 16
  • 15