简体   繁体   中英

Wait until panel controls are drawn

I have a form, this form has a panel. When the form OnShown fires, I start a background worker to execute a long running code method a set number of times. In this background worker, I add a User Control to the panel one-by-one/per-iteration while displaying a Wait picture on the UI thread.

Problem: My long running code runs faster than the panel can draw the controls I've added to it. Basically, when my form loads, it takes about 1.5 seconds to run the code (I can tell by how fast the wait picture hides itself), however, the child controls on the panel take between 4 and 6 seconds to draw themselves...

As you can imagine this would cause some major confusion to the user in that the Wait image would hide/the code would be done, but the controls wouldn't be shown for another 4 seconds.

So, is there a way to essentially "Wait" until all the child controls on the panel are drawn, so that i can ONLY THEN hide the Wait picture through some mechanism in the Panel control?

If that's not possible, keep in mind that I'm using a User Control and have access to those events as well. So if there's something there I could use to fire AFTER the User Control has drawn itself (or thinks it has), maybe i could use that instead and count until I reach the known count?

Here's my code, obscured a bit to not show any work info/not tell you what I'm doing but should be enough for you to find out if there's something wrong with the code itself...

Legend:

SW() = Show Waiting Picture,

HW() = Hide Waiting Picture,

this.wait = Wait Picture Control with progress bars...

private void MyForm_Shown(object sender, EventArgs e)
        {
            if (this.SomeList.Count <= 0 || this.SomeObject == null)
                this.DialogResult = DialogResult.Abort;

            SW();

            this.wait.Text = "Loading everything...";
            this.wait.TotalBar_Max = this.SomeList.Count;
            this.wait.TotalBar_Value = 0;
            this.wait.CurrentBar_Max = 100;

            BackgroundWorker bkg = new BackgroundWorker();
            bkg.DoWork += new DoWorkEventHandler(bkg_DoWork);
            bkg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bkg_RunWorkerCompleted);
            bkg.RunWorkerAsync();

        }


        void bkg_DoWork(object sender, DoWorkEventArgs e)
        {
            foreach (SomeType SomeItem in this.SomeList)
            {
                //Update Progress bar...
                this.Invoke(new MethodInvoker(delegate
                {
                    this.wait.Text = "Loading Specifics for: " + SomeItem.ToString();
                    this.wait.CurrentBar_Value = 50;
                }));


                MyControl tmp = new MyControl();
                tmp.Name = SomeItem.ToString();
                tmp.Text = SomeItem.ToString() + " - " + this.SomeObject.Name;

                ServerWorker work = new ServerWorker(SomeItem);

                Dictionary<string, List<string>> test = work.LongRunningCode();
                //fill in/Init User Control based on long running code results...
                if (test["Key1"] != null && test["Key1"].Count > 0)
                {
                    test["Key1"].Sort();
                    tmp.Key1 = test["Key1"];
                }
                else
                {
                    tmp.Key1_Available = false;
                }
                if (test["Key2"] != null && test["Key2"].Count > 0)
                {
                    test["Key2"].Sort();
                    tmp.Key2 = test["Key2"];
                }
                else
                {
                    tmp.Key2_Available = false;
                }
                if (test["Key3"] != null && test["Key3"].Count > 0)
                {
                    test["Key3"].Sort();
                    tmp.Key3 = test["Key3"];
                }
                else
                {
                    tmp.Key3_Available = false;
                }

                //Add user control, and update progress bars...
                this.Invoke(new MethodInvoker(delegate
                            {
                                if (this.panel1.Controls.Count <= 0)
                                {
                                    tmp.Top = 5;
                                    tmp.Left = 5;
                                }
                                else
                                {
                                    tmp.Top = this.panel1.Controls[this.panel1.Controls.Count - 1].Bottom + 5;
                                    tmp.Left = 5;
                                }

                                this.panel1.Controls.Add(tmp);
                                this.wait.Text = "Loading Specifics for: " + SomeItem.ToString();
                                this.wait.CurrentBar_Value = 100;
                                this.wait.TotalBar_Value += 1;
                                this.panel1.Refresh();
                            }));

            }

            e.Result = true;
        }

        void bkg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            HW();
        }

I found my own solution here:

https://stackoverflow.com/a/6653042/1583649

By building a List within the background worker instead of Invoking the UI thread, and then Panel.Add() on the RunWorkerCompleted event instead, the Wait image was able to stay alive until all the controls were actually drawn on the Panel.

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