【问题标题】:n clicks on a button gives n outputs. Required is only one output resulting from one clickn 点击按钮给出 n 个输出。只需单击一次即可产生一个输出
【发布时间】:2015-05-27 15:58:31
【问题描述】:

好的..所以我不知道为什么会发生这种情况。我猜我在Java中看到了类似的问题..但我不明白这些东西。我正在使用 C#,我有一个 listview,它在单击按钮时使用远程服务器更新状态进行更新。我有为此工作的代码。但是当我再次单击同一个按钮时,输出显示两次。如果我再点击一次,输出会显示三次,依此类推!! 例如: 第一次点击:

xxx     login to server failed
yyy     login to server failed

第二次点击:

xxx     login to server failed
xxx     login to server failed
yyy     login to server failed
yyy     login to server failed

我正在使用backgroundworker,并在其中使用并行foreach 循环。我已将所有相关函数都放在这里,以便那里有所有信息。抱歉,如果这太多了! 这是我的代码:

    private void button1_Click(object sender, EventArgs e)                        //get update button
    {
        GlobalVariables._count = 0;
        Status.statusProgress obj1 = new Status.statusProgress();
        if (getupdate_button.Text == "Stop")
        {
            backgroundWorker1.CancelAsync();
            getupdate_button.Enabled = false;
        }
        else
        {
            getupdate_button.Text = "Stop";
            listView1.Items.Clear();
            //do stuff
            backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
        }
        if (backgroundWorker1.IsBusy)
        {
            if (backgroundWorker1.CancellationPending != true)
            {
                MessageBox.Show("Please wait till the pervious operation is completed!");
            }
            else 
            {
                Complete_label.Text = "Cancelling...";
                Complete_label.Visible = true;
            }
        }
        else
        {
            backgroundWorker1.RunWorkerAsync(obj1);                                //calling background worker
        }
    }

工作:

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)                         //the boss-- the background worker
    {
        System.ComponentModel.BackgroundWorker worker;
        worker = (System.ComponentModel.BackgroundWorker)sender;
        Status obj1 = new Status();
        Status.statusProgress obj = new Status.statusProgress();

        if ((backgroundWorker1.CancellationPending == true))
        {
            e.Cancel = true;
        }
        else
        {
            obj1.Calculation(worker, e);
        }
        e.Result = obj;
    }

计算方法:

    public void Calculation(System.ComponentModel.BackgroundWorker worker, System.ComponentModel.DoWorkEventArgs e)
    {
        Status.statusProgress obj = (Status.statusProgress)e.Argument;
        //stuff

            var file = File.ReadAllLines(obj.SourceFile);

            List<string> namelist = null;
            namelist = new List<string>(file);
            Parallel.ForEach(namelist, /*new ParallelOptions { MaxDegreeOfParallelism = 4 }, */line =>
            //foreach (string line in namelist)
            {
                var progress = new statusProgress();
                progress.TotalSysCount = obj.TotalSysCount;
                Status.statusProgress result = new Status.statusProgress();
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    worker.ReportProgress(result.SysCount, result);
                }
                else
                {
                    //this.SystemName = line;//file.ReadLine();                        
                    progress.SystemName = line;
                    //result = progress;
                    result = OneSystem(line);
                    //work with result
        }
                count1 = Interlocked.Increment(ref count);
                //stuff
                worker.ReportProgress(count1, progress);
                Thread.Sleep(200);

             });

        }
    }

报告进度方法:

     private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
    try
                {
                    var newItem = listView1.Items.Add("");
                    newItem.SubItems.Add(result.SystemName);
                    newItem.SubItems.Add(result.StatusString);
                    newItem.SubItems.Add(result.AvailableUpdatesCount.ToString());
                }
                catch (Exception ex)
                {}

            update_text(result);
            progressBar1.Maximum = 100;
            int perc = (int)((result.SysCount * 100) / result.TotalSysCount);
            progressBar1.Value = perc;
            Complete_label.Text = perc.ToString()+"%";
            if (progressBar1.Value == 100)
            {
                Complete_label.Text = "Complete!";
                getupdate_button.Enabled = false;
            }
    }

【问题讨论】:

  • 哇,我已经厌倦了写“给我们一些代码!”一遍又一遍...... “对不起,如果那太多了!这是我的代码:” 太令人耳目一新了:)
  • 您能否发布初始化backgroundWorker1 的代码,我怀疑您可能重复订阅了某个事件。 backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
  • @Hari Prasad 我不知道初始化 backgroundworker1 代码是什么意思。我只是使用 Visual Studio 的工具箱添加它...我有定义:private System.ComponentModel.BackgroundWorker backgroundWorker1;
  • @Aditi 你的代码中必须有类似var backgroundWorker1 = new BackgroundWorker();
  • 考虑使用 Completed 事件而不是 if (progressBar1.Value == 100)。用于正确处理错误和取消。

标签: c# multithreading winforms backgroundworker


【解决方案1】:

我猜问题出在这里:

backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;

如果您每次执行整个单击 操作时都添加一个ProgressChanged 事件处理程序,那么在每次单击后,您将增加事件被处理的次数。

归根结底,您应该在某些应用程序的初始化代码或类构造函数中添加事件处理程序,而不是在单击事件处理程序中这样做。也就是说,您将确保在每个应用程序生命周期中添加一次 backgroundWorker1_ProgressChanged 事件处理程序。

【讨论】:

  • 和/或每次只创建一个新的Backgroundworker。它们很便宜,它使您无需跟踪所有状态。
  • 我想你已经搞定了。我总是在这样的前提下工作,如果我的代码执行 += 来添加一个处理程序,我也会确保我执行 -= 以在不需要时将其删除。
  • @Enigmativity 也许删除事件处理程序可能是一个解决方案,但要注意使这个线程安全,因为如果许多线程添加处理程序并删除处理程序会发生什么......? :D
  • 我最初是这么认为的.. 但即使注释掉该特定行也会出现同样的问题。
  • 我在调用后台工作人员后也尝试了一个 -= ......但它也没有工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-17
  • 1970-01-01
  • 2022-06-22
  • 1970-01-01
  • 2019-04-22
  • 1970-01-01
  • 2022-08-19
相关资源
最近更新 更多