【问题标题】:Wait until panel controls are drawn等到面板控件被绘制
【发布时间】:2014-03-01 02:18:18
【问题描述】:

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

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

正如您可以想象的那样,这会给用户带来一些重大的困惑,因为等待图像会隐藏/代码会完成,但控件不会再显示 4 秒。

那么,有没有办法基本上“等待”,直到面板上的所有子控件都被绘制,这样我才能通过面板控件中的某种机制隐藏等待图片?

如果这不可能,请记住我使用的是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 我以为你有一个经过充分研究和解释的问题。不知道你为什么投了反对票。
  • 我也这么认为...谢谢!

标签: c# multithreading


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 1970-01-01
    • 2012-01-15
    相关资源
    最近更新 更多