简体   繁体   中英

C# - Form freezing after about 30 seconds - Multithreading

I'm currently working on a project with two forms and a tray icon. However I'm having trouble when displaying the second form, Form2, that it simply freezes about 30 seconds after being displayed in a certain way.

The first form (Form1) is always displayed in the background, with only two thin red buttons covering about 7 pixels on each side of the user's monitor and the space in between is transparent. The buttons are meant to flash when an alarm is going off and they do so successfully using the code below.

After this Task is run, a new Form2 is created. Form2 displays information about the alarm that is going off and allows acknowledgement, which also stops the red bars from flashing. Form2 is created just after Form1's Opacity task is run. The below code is the Main function of Program.cs

        redBarForms = new List<Form1>();
        foreach (var screen in Screen.AllScreens)
        {
            var form = new Form1();
            form.Opacity = 0d;
            form.Show();

            form.WindowState = FormWindowState.Normal;
            form.Location = screen.WorkingArea.Location;
            form.WindowState = FormWindowState.Maximized;

            redBarForms.Add(form); // Only one is added right now, working from one screen
        }

        // Begin the loop which checks to see if the bars should be flashing. 
        Task.Run(() =>
        {
            while (true)
            {
                while (flashingAlertBars)
                {
                    for (int i = 1; i <= 100; i++)
                    {
                        foreach (var form in redBarForms)
                        {
                            form.Invoke(new Action(() =>
                            {
                                form.Opacity = i / 100d;
                            }));
                            i += 9;
                        }
                        Thread.Sleep(50);
                    }

                    for (int i = 100; i >= 1; i--)
                    {
                        foreach (var form in redBarForms)
                        {
                            form.Invoke(new Action(() =>
                            {
                                form.Opacity = i / 100d;
                            }));
                            i -= 9;
                        }
                        Thread.Sleep(50);
                    }
                }
            }
        });

        MainForm = new Form2();

        // Start the updater on a background worker so that it doesn't 
           affect the UI thread
        BackgroundWorker bgUpdater = new BackgroundWorker();
        bgUpdater.WorkerSupportsCancellation = true;
        bgUpdater.DoWork += Updater_BGWorker_DoWork;
        bgUpdater.RunWorkerAsync();

        // Start Form1
        if (!redBarForms[0].IsDisposed)
        {
            redBarForms[0].Invoke(new Action(() =>
            {
                Application.Run(redBarForms[0]);
            }));
        }

After both forms are created, I've got a class, Updater, that is run on a BackgroundWorker (bgUpdater), which gets a list of which alarms are going off from a web API every 10 seconds, then makes this member public in its class. Form2 has a BackgroundWorker itself that then pulls this member from Updater on another 10 second interval and uses it to create clickable labels and display information about each current alarm in its form.

Updater has a feature to send a toast notification when an alarm is detected, and has a button to open Form2 to the correct page where an acknowledgement can be sent. The toast notification button's click event runs the following method to open the form to the correct page:

    static public void ShowManagementUI(Result monitor)
    {
        if (Application.OpenForms.OfType<Form2>().Count() > 0)
        {
            if (MainForm.InvokeRequired)
            {
                MainForm.Invoke(new Action(() =>
                {
                    MainForm.ShowWithResult(monitor); //This just does an Activate()
                }));
            }
        }
        else
        {
            if (MainForm.IsDisposed)
                MainForm = new Form2();
            MainForm.Show();
            MainForm.ShowWithResult(monitor); //This just does an Activate()
        }

    }

When displaying Form2 just by opening the form normally (Form2.Activate()), there is no issue and the form does not freeze, however when displaying the form using ShowManagementUI(Result monitor), Form2 freezes after anywhere between 10-30 seconds, but Form1 keeps on flashing its red bars. It doesn't throw any exceptions, but I have a feeling it's probably attempting to Invoke an operation on the UI thread but it's locked for one reason or another.

I cannot for the life of me find why it would be doing this. Does anyone have any suggestions on tracking down a freeze like this?

Call Application.DoEvents in the opacity increasing for loop in order to give UI thread a chance to render changes. Also 50ms interval is small. Try bigger numbers.

But generally, this is not a good idea for animation :P

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM