【问题标题】:How to create and add controls in run time with BackgroundWorker如何使用 BackgroundWorker 在运行时创建和添加控件
【发布时间】:2018-03-17 09:53:55
【问题描述】:

我不知道如何使用 WinForms 中的 BackgroundWorker 来实现具有单独线程的方法。 我希望执行此方法(每次单击按钮后):

  • 创建 ProgressBar(每个新的在前一个之下)
  • 创建位图和BackgroundWorker
  • 使用 BackgroundWorker 在单独的线程中设置该位图中每个像素的颜色
  • 在 ProgressBar 上显示百分比进度
  • 完成后:在背景上创建一个带有位图的新表单
  • 完成后:移除 ProgressBar

我的代码:

    List<BackgroundWorker> Workers;
    List<ProgressBar> Progress;
    int OperationsCount = 0;
    private void ShowProgress(int n, int percent)
    {
        Progress[n].Value = percent;
    }
    private void Blend(object sender, DoWorkEventArgs e)
    {
        Bitmap BlendedImage = ... // creates a bitmap
        for (int i = 0; i < BlendedImage.Width; i++)
        {
            for (int j = 0; j < BlendedImage.Height; j++)
            {
                ... //changing colour of every pixel
            }
            this.Invoke(new Action(()=>ShowProgress((int)e.Argument, (int)(100 * (double)(i/BlendedImage.Width)))));
        }

        Form BlendedImage_Form = new Form();
        BlendedImage_Form.Size = new Size(BlendedImage.Width, BlendedImage.Height);
        BlendedImage_Form.BackgroundImage = BlendedImage;
        BlendedImage_Form.BackgroundImageLayout = ImageLayout.Stretch;
        this.Invoke(new Action(() => BlendedImage_Form.Show()));

    }        
    private void PerformBlending_Button_Click(object sender, EventArgs e)
    {
        int n = OperationsCount++;
        Progress.Add(new ProgressBar());
        Progress[n].Size = ...
        Progress[n].Location = ...
        Progress[n].Maximum = 100;
        this.Controls.Add(Progress[n]);

        Workers.Add(new BackgroundWorker());
        Workers[n].DoWork += new DoWorkEventHandler(Blend);
        Workers[n].RunWorkerCompleted += (object _sender, RunWorkerCompletedEventArgs _e) => 
        {
            //OperationsCount--;
            //Progress[n].Dispose();
            //this.Controls.Remove(Progress[n]);
            //Progress.RemoveAt(n);
        };
        Workers[n].RunWorkerAsync(n);
    }

当我只单击一次按钮时,一切似乎都很好,但是当我单击两次按钮时,然后编程:

  • 创建第一个正确显示进度的 ProgressBar,并且新表单和位图也正确显示
  • 创建了第二个 ProgressBar,但它根本不显示进度,也没有显示任何表单和位图。

PS 我宁愿使用 BackgroundWorker 而不是其他工具。

【问题讨论】:

  • 你在哪里实例化这些列表?
  • 所有 UI 工作都应该在主线程上。即使您使用的是 BackgroundWoker,您也需要修改主线程上的控件。
  • @Groo in public MainWindow()
  • (double)(i/BlendedImage.Width) 是一个标准的 C# 错误,它总是产生 0。你必须要求浮点除法,((double)i / BlendedImage.Width)
  • @Adrian 那么如何在改变像素颜色后返回位图呢?我需要它在我的表单中显示它

标签: c# multithreading winforms


【解决方案1】:

根据您的评论,这里是解决方案

 public void DoSomething()
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(()=> DoSomething()));
            }
            else
            {
               // update the ui from here, no worries
            }
        } 

在这段代码中,我正在修改主线程上的对象。如果从非 UI 线程进行调用,这将进入 InvokeRequired。

// 来自您在评论中给出的这段代码

https://pastebin.com/45jQXCt9

请尝试在调用中创建实例。它应该可以工作。

【讨论】:

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