【问题标题】:Need help with threading -C# Windows Forms需要线程方面的帮助 -C# Windows 窗体
【发布时间】:2010-10-21 14:32:46
【问题描述】:

我正在尝试创建一个包含表单进度条(只是 GIF 图像)的线程。 我已经在一个大方法之前调用了StartProgress()。基本上,当线程启动时,它会加载 ProgressBar 表单(我想一直显示,并在不需要时将其隐藏)并且 ProgressActive 设置为 true,它应该显示表单,直到 ProgressActive 为 false ,然后表单应该被隐藏(直到进度再次处于活动状态)。这是我到目前为止所拥有的,但它冻结了我:(

    public static string ProgressInfo="Test";
    public static bool ProgressActive=true;
    public static bool ThreadStarted = false;

    public static void StartProgress()
    {
        while (!ThreadStarted)
        {
            Thread t = new Thread(new ThreadStart(Progress));
            ThreadStarted = true;
            t.Start();
        }

    }
    public static void Progress()
    {
        while (ThreadStarted)
        {

            LoadingBar lb = new LoadingBar();
            lb.Show();
            lb.TopMost = true;
            while (ThreadStarted)
            {
                if (ProgressActive)
                {
                    lb.Visible = true;
                    lb.lblLoadingStatus.Text = ProgressInfo;
                }
                else
                {
                    lb.Visible = false;
                }
                Thread.Sleep(1000);
            }
        }

    }

编辑:我正在尝试在静态类中执行此操作。

【问题讨论】:

    标签: c# winforms multithreading


    【解决方案1】:

    如果使用 .NET 2.0 或更高版本,是否有任何理由不使用 BackgroundWorker?

    我这么说的原因是因为 BackgroundWorker 是基于事件的,所以它暴露了一个像 ProgressChanged 这样的事件,可以减少代码的整体大小。

    【讨论】:

    • 原因是我错过了它。使用带有 BG 的 ProgressChanged 之类的事件仍然有点迷失编辑:注意我正在尝试在一个完整的静态类中实现这一点
    【解决方案2】:

    冻结是由于您试图从工作线程更改 UI 线程中包含的进度条。我建议从你的工作进程函数中引发一个事件到 UI 线程上的处理程序。您需要将调用编组到线程上的处理程序,如下所示。

    private object _lock = new object(); //should have class scope
    
    private void ShowProgressControl(EventArgs e)
    {
      if (this.InvokeRequired)
      {
        lock (_lock)
        {
          EventHandler d = new EventHandler(ShowProgressControl);
          this.Invoke(d, new object[] { e });
          return;
        }
      }
      else
      {
        //Show your progress bar.
      }
    }
    

    享受吧!

    【讨论】:

    • 谢谢,但我使用的是静态类,所以“this”不起作用:(
    • @Spooks - 您可能需要考虑只为您的工作进程使用该静态类,让它公开和事件,然后在(UI 线程)上托管您的应用程序的主窗体中使用该事件。
    • 这听起来是个好主意。就在我做 Thread t = new Thread(new ThreadStart(Progress));这会创建一个新的工作进程(不消耗 UI 线程)吗?
    • @Spooks - 当你做一个线程时是的 t = new Thread(new ThreadStart(Progress));这将创建一个新线程,该线程可以独立于运行主窗体的 ui 线程来处理工作。我上面概述的方法将为您提供最大的灵活性。
    【解决方案3】:

    问题是任何 UI 元素都需要一个消息循环才能正常工作。由于您是在工作线程中创建表单,因此没有运行消息循环。要创建消息循环,您必须调用 Application.Run 或 Form.ShowDialog 两者都是阻塞调用。显然,该解决方案会挂起您的工作线程。

    最好的办法是创建一个单独的线程,专门用于运行消息循环并且可以安全地处理表单和控件。让工作线程定期将进度信息发布到可以在工作线程和 UI 线程之间共享的变量。然后让 UI 线程定期轮询(使用 System.Windows.Form.Timer)该共享变量并相应地更新 UI。

    附带说明,我会避免使用Control.Invoke 或Control.BeginInvoke 将进度信息推送到UI 线程。您的情况似乎需要轮询方法。选择轮询而不是推送的原因是:

    • 它打破了Control.Invoke 强加的 UI 和工作线程之间的紧密耦合。
    • 它将更新 UI 线程的责任放在它本来应该属于的 UI 线程上。
    • UI 线程可以决定更新的时间和频率。
    • 不存在 UI 消息泵溢出的风险,就像工作线程启动的封送处理技术那样。
    • 工作线程无需等待确认更新已执行,即可继续执行后续步骤(即,您可以在 UI 和工作线程上获得更高的吞吐量)。

    【讨论】:

      【解决方案4】:

      你应该在主线程上创建进度条。

      确保您的繁重程序从另一个线程运行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-22
        • 1970-01-01
        • 2011-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多