【问题标题】:ProgressBar form hangs on the middle, value updated from BackGroundWorker classProgressBar 窗体挂在中间,值从 BackGroundWorker 类更新
【发布时间】:2014-07-24 03:43:21
【问题描述】:

我创建了一个带有 button1 的 form1 来启动一个任务,它将在后台使用 BackGroundWorker 在一个单独的类上进行处理,并在一个单独的窗口上显示一个 ProgressBar。

我的问题是进程运行正常,只是任务完成但进度条形式挂在中间。

下面是BackGroundLoading类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.ComponentModel;

namespace sample2
{
    public class BackgroundLoading
    {
        public BackgroundWorker Bw;
        public delegate void RunFunction();
        public RunFunction thisFunction;
        mycontrols.LoadProgress p = new mycontrols.LoadProgress();

        public BackgroundLoading(RunFunction newFunction)
        {
            thisFunction = newFunction;
            Bw = new BackgroundWorker();
            Bw.WorkerReportsProgress = true;
            Bw.DoWork += new DoWorkEventHandler(Bw_DoWork);
            Bw.ProgressChanged += new ProgressChangedEventHandler(Bw_ProgressChanged);
            Bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Bw_RunWorkerCompleted);
        }

        public void Start()
        {
            Bw.RunWorkerAsync();
        }

        void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show("Error: " + e.Error.Message);
            }
            if (e.Cancelled)
            {
                MessageBox.Show("Cancelled!");
            }
            else
            {
                MessageBox.Show("Completed!");
                p.Close();
            }

        }

        public void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            /// If I put 
            /// p.ProgBar.Value = e.ProgressPercentage;
            /// the progressbar hangs upon form show.
        }

        void Bw_DoWork(object sender, DoWorkEventArgs e)
        {
            p.Show();

            BackgroundWorker worker = sender as BackgroundWorker;

            for (int i = 1; (i <= 100); i++)
            {
                if ((worker.CancellationPending == true))
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    if (thisFunction != null)
                    {
                        thisFunction();
                        worker.ReportProgress((i * 1));
                        p.ProgBar.Value = i;   
                    }
                    else
                    {
                        MessageBox.Show("Error, no method found");
                    }
                }
            }

        }
    }
}

这是 Form1 代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace sample2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            BackgroundLoading BL = new BackgroundLoading(workingmethod);
            BL.Start();
        }

        private void workingmethod()
        {
            System.Threading.Thread.Sleep(10);
        }

    }
}

这是 LoadProgress 表单的代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace sample2.mycontrols
{
    public partial class LoadProgress : Form
    {
        public LoadProgress()
        {
            InitializeComponent();
        }

        private void LoadProgress_Load(object sender, EventArgs e)
        {     

        }

    }
}

进度条表单上没有代码,因为更新是在类上完成的。 找不到挂起的原因。

提前致谢。

【问题讨论】:

  • 您是否尝试过将p.Show(); 移出Bw_DoWork 事件处理程序(BackgroundLoading ctor 可能会起作用)?不应从后台线程访问 WinForms 控件(DoWork 在非 UI 后台线程上触发)。从 UI 线程以外的任何线程访问 Form 或 UserControl 属性会导致不可预知的行为 - p.ProgBar.Value = i; 也是如此(您可以在正确编组到 UI 线程的 ProgressChanged 事件中更新它)
  • 您是否尝试过调试您的代码?
  • 您正在从非 UI 线程访问 UI。改用 Invoke():p.Invoke(new MethodInvoker(delegate { p.ProgBar.Value = e.ProgressPercentage; }));

标签: c# winforms class progress-bar backgroundworker


【解决方案1】:

在运行 BackgroundWorker 之前,在主 UI 线程上显示表单:

public void Start()
{
    p.Show();

    Bw.RunWorkerAsync();
}

然后您可以在ProgressChanged 事件中调用表单,该事件在 UI 线程上运行。

从 DoWork 事件中删除 p.Show() 和 p.ProgBar.Value = i; - 您不想从后台线程中触摸 UI 线程。

public void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    p.ProgBar.Value = e.ProgressPercentage;
}

最后,在BackgroundWorker 完成时关闭表单(您已经在这样做了):

void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    p.Close();
}

【讨论】:

  • 谢谢你,先生,你救了我这个.. :)
猜你喜欢
  • 1970-01-01
  • 2016-02-24
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 2010-12-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多