等到绘制面板控件

时间:2014-02-28 16:15:52

标签: c# multithreading

我有一个表格,这个表格有一个面板。当表单OnShown触发时,我启动后台工作程序以执行一组长时间运行的代码方法。在这个后台工作者中,我在UI线程上显示等待图片时,逐个/每次迭代向面板添加User Control

问题:我的长时间运行代码的运行速度比面板可以绘制我已添加的控件的速度快。基本上,当我的表单加载时,运行代码大约需要1.5秒(我可以判断等待图片隐藏的速度有多快),但是,面板上的子控件需要4到6秒才能自行绘制......

你可以想象这会给用户带来一些重大的混淆,因为等待图像会隐藏/代码会被完成,但控件不会再显示4秒。

那么,有没有办法实现"等待"直到绘制了面板上的所有子控件,这样我才能通过Panel控件中的某些机制隐藏Wait图片?

如果无法做到这一点,请记住我使用User Control并且也可以访问这些事件。因此,如果在用户控件已经绘制自己(或认为它有)之后我可以用它来触发,那么也许我可以使用它来计算直到我达到已知计数?

这是我的代码,有点模糊,没有显示任何工作信息/没有告诉你我在做什么,但应该足以让你知道是否有什么问题。代码本身......

传奇:

SW() = Show Waiting Picture,

HW() = Hide Waiting Picture,

带进度条的

this.wait = Wait Picture Control ...

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();
        }

1 个答案:

答案 0 :(得分:0)

我在这里找到了自己的解决方案:

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

通过在后台工作程序中构建List而不是调用UI线程,然后在RunWorkerCompleted事件上构建Panel.Add(),Wait图像能够保持活动状态,直到在Panel上实际绘制了所有控件。