0

我的主要问题是,当我在 flowLayoutPanel1 上为每个请求动态添加进度条时,如何从backgroundWorker1_ProgressChanged 事件中增加正确的进度条值

当用户单击开始按钮时,我将调用后台工作者的 RunWorkerAsync 函数....很好。在这里,我正在编写示例代码并尝试显示我的问题。

我的表单有一个文本框、一个按钮和一个带有 FlowDirection 自上而下的 flowLayoutPanel1。

当用户在文本框中输入任何 url 并单击开始按钮时,我将使用 BackGroundWorker 开始文件下载,并在 flowLayoutPanel1 上动态添加一个进度条。一次可以下载10个文件。因此,当用户一个接一个地输入十个网址并单击提交按钮时,十个文件将在后台下载。

我的问题是如何从 backgroundWorker1_ProgressChanged 事件中正确增加 10 个进度条进度另一个问题是当任何文件下载完成时,已创建它的进度条将从面板中删除

这是我的完整代码。请看看并告诉我我需要做什么来完成我的任务。如果有人看到我的代码中可能出现死锁的问题,那么也请指导我如何避免死锁。这是我的代码

public partial class Form1 : Form
    {
        static int pbCounter = 1;

        public Form1()
        {
            InitializeComponent();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            ProgressBar pb = new ProgressBar();
            if (pbCounter <= 10)
            {
                pb.Width = txtUrl.Width;
                flowLayoutPanel1.Controls.Add(pb);
                pbCounter++;

                System.ComponentModel.BackgroundWorker backgroundWorker1 = new System.ComponentModel.BackgroundWorker();

                backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
                backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
                backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);

                backgroundWorker1.RunWorkerAsync();
            }
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            // Get the BackgroundWorker that raised this event.
            System.ComponentModel.BackgroundWorker worker = sender as System.ComponentModel.BackgroundWorker;

            // Assign the result of the computation
            // to the Result property of the DoWorkEventArgs
            // object. This is will be available to the  
            // RunWorkerCompleted eventhandler.
            //#e.Result = ComputeFibonacci((int)e.Argument, worker, e);
        }

        // This event handler deals with the results of the
        // background operation.
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // First, handle the case where an exception was thrown.
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else if (e.Cancelled)
            {
                //# "Canceled";
            }
            else
            {
                pbCounter--;
                // Finally, handle the case where the operation  
                // succeeded.
                //#resultLabel.Text = e.Result.ToString();
            }
        }

        // This event handler updates the progress bar.
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.progressBar1.Value = e.ProgressPercentage;
        }

    }

我更新的部分

 public partial class Form1 : Form
    {
        static int pbCounter = 1;

        public Form1()
        {
            InitializeComponent();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            ProgressBar pb = new ProgressBar();
            if (pbCounter <= 10)
            {
                //pb.Step = 10;
                pb.Minimum = 0;
                //pb.Maximum = 100;
                pb.Width = txtUrl.Width;
                flowLayoutPanel1.Controls.Add(pb);
                pbCounter++;

                MyBackgroundWorker backgroundWorker1 = new MyBackgroundWorker();
                backgroundWorker1.pbProgress = pb;
                backgroundWorker1.WorkerReportsProgress = true;   
                backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
                backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
                backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);

                backgroundWorker1.RunWorkerAsync(txtUrl.Text);
            }
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            int input = int.Parse(e.Argument.ToString());
            for (int i = 1; i <= input; i++)
            {
                Thread.Sleep(2000);
                 (sender as MyBackgroundWorker).ReportProgress(i * 10);
                 if ((sender as MyBackgroundWorker).CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }
            }
        }

        // This event handler deals with the results of the 
        // background operation. 
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // First, handle the case where an exception was thrown. 
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else if (e.Cancelled)
            {
                //# "Canceled";
            }
            else
            {
                ProgressBar pb = (sender as MyBackgroundWorker).pbProgress;
                if (pb != null)
                {
                    //pb.Value = 100;
                    //pb.Update();

                    while (pb.Value <= pb.Maximum)
                    {
                        //Thread.Sleep(1000);
                        flowLayoutPanel1.Controls.Remove(pb);
                        break;
                    }

                }
                // Finally, handle the case where the operation  
                // succeeded.
            }
        }

        // This event handler updates the progress bar. 
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ProgressBar pb = (sender as MyBackgroundWorker).pbProgress;
            pb.Refresh();

            //if (e.ProgressPercentage < pb.Maximum)
            //    pb.Value = e.ProgressPercentage + 10;

            pb.Value = e.ProgressPercentage ;
            Application.DoEvents();

        }

    }

public class MyBackgroundWorker : System.ComponentModel.BackgroundWorker
    {
        public ProgressBar pbProgress = null;
        public MyBackgroundWorker()
        {
        }

        public MyBackgroundWorker(string name)
        {
            Name = name;
        }

        public string Name { get; set; }
    }
4

2 回答 2

1

这是一种方法——

创建自己的继承自 BackgroundWorker 的类,添加 ProgressBar 类型的公共变量。

每次动态添加 BackgroundWorker 和 Progressbar 时,将 progressbar 对象传递给您的类。

您的派生类 -

public class MyBackgroundWorker : BackgroundWorker
{
    public ProgressBar pbProgress = null;

    public void BackgroundWorker()
    {
    }
}

按钮事件代码 -

private void btnStart_Click(object sender, EventArgs e)
{
    ProgressBar pb = new ProgressBar();
    if (pbCounter <= 10)
    {
        pb.Width = txtUrl.Width;
        flowLayoutPanel1.Controls.Add(pb);
        pbCounter++;

        MyBackgroundWorker backgroundWorker1 = new MyBackgroundWorker();
        backgroundWorker1.pbProgress = pb;

        backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
        backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
        backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);

        backgroundWorker1.RunWorkerAsync();
    }
}

进度改变事件 -

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        (sender as MyBackgroundWorker).pbProgress.Value = e.ProgressPercentage;
    }
于 2013-03-28T10:50:46.543 回答
1

首先声明一个全局字典和一个GetInstance方法来访问表单实例

public partial class Form1 : Form
{
Dictionary<String, ProgressBar> progressBars = new Dictionary<String, ProgressBar>();

static Form1 _form1 = null;

static int pbCounter = 1;

public Form1()
{
    InitializeComponent();
    _form1 = this;
}

public static Form1 GetInstance() {
    return _form1;
}

然后使用您获得的每个网址,您必须为每个网址创建 pb,只需将它们添加到此字典中

progressBars.Add("file1", pb1);
progressBars.Add("file2", pb2);
progressBars.Add("file3", pb3);
progressBars.Add("file4", pb4);

在 form.cs 中创建一个函数,您可以在其中传递进度条,然后您可以手动设置它的值。

public void ProgessReport(ProgressBar pb, int value) 
        {
            if (pb.InvokeRequired) 
            {
                pb.Invoke(new MethodInvoker(delegate { ProgessReport(pb, value); }));
            } else 
            {
                pb.Value = value;
            }
        }

现在从你下载文件的地方你只需要调用

Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file1"], 10);
Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file1"], 20);
Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file1"], 100);

and when your second file downloads then

Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file2"], 10);
Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file2"], 20);
Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file2"], 100);

像这样 ..

于 2013-03-28T10:52:58.223 回答