C# 如何使用BackgroundWorker在运行时创建和添加控件
我不知道如何使用WinForms中的BackgroundWorker使用单独的线程实现方法。 我希望此方法(每次单击按钮后)执行:C# 如何使用BackgroundWorker在运行时创建和添加控件,c#,multithreading,winforms,C#,Multithreading,Winforms,我不知道如何使用WinForms中的BackgroundWorker使用单独的线程实现方法。 我希望此方法(每次单击按钮后)执行: 创建ProgressBar(前一个下的每个新的) 创建位图和BackgroundWorker 使用BackgroundWorker在单独的线程中设置位图中每个像素的颜色 在进度栏上显示进度 完成后:使用位图在后台创建一个新表单 完成后:卸下进度条 我的代码: List<BackgroundWorker> Workers; List&l
- 创建ProgressBar(前一个下的每个新的)
- 创建位图和BackgroundWorker
- 使用BackgroundWorker在单独的线程中设置位图中每个像素的颜色
- 在进度栏上显示进度
- 完成后:使用位图在后台创建一个新表单
- 完成后:卸下进度条
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);
}
列出工人名单;
列出进度;
整数运算计数=0;
私有void ShowProgress(整数n,整数百分比)
{
进度[n]。值=百分比;
}
私有void混合(对象发送方,DoWorkEventArgs e)
{
位图BlendedImage=…//创建位图
对于(int i=0;iShowProgress((int)e.Argument,(int)(100*(double)(i/BlendedImage.Width)()));
}
Form BlendedImage_Form=新表单();
BlendedImage_Form.Size=新尺寸(BlendedImage.Width、BlendedImage.Height);
BlendedImage_Form.BackgroundImage=BlendedImage;
BlendedImage_Form.BackgroundImageLayout=ImageLayout.Stretch;
调用(新操作(()=>BlendedImage_Form.Show());
}
私有void PerformBlending按钮单击(对象发送者,事件参数e)
{
int n=操作计数++;
Progress.Add(新的ProgressBar());
进度[n]。大小=。。。
进度[n]。位置=。。。
进度[n]。最大值=100;
此.Controls.Add(进度[n]);
添加(新BackgroundWorker());
工人[n].DoWork+=新的DoworkerVenthandler(混合);
Workers[n]。RunWorkerCompleted+=(对象\u发送方,RunWorkerCompletedEventArgs\u e)=>
{
//操作计数--;
//进程[n].Dispose();
//此.Controls.Remove(进度[n]);
//进展。移除(n);
};
Workers[n].RunWorkerAsync(n);
}
当我只点击一次按钮时,一切似乎都很好,但当我点击两次按钮时,程序:
- 创建正确显示进度的第一个进度条,并正确显示新表单和位图
- 创建第二个进度条,但它根本不显示进度,并且不显示任何窗体和位图
PS我宁愿使用BackgroundWorker而不是其他工具。根据您的评论,这里是解决方案
public void DoSomething()
{
if (this.InvokeRequired)
{
this.Invoke(new Action(()=> DoSomething()));
}
else
{
// update the ui from here, no worries
}
}
在这段代码中,我正在修改主线程上的对象。如果从非UI线程进行的调用将进入InvokeRequired
//根据您在注释中给出的代码
请尝试在调用内部创建实例。它应该可以工作。在哪里实例化这些列表?所有UI工作都应该在主线程上。即使您正在使用BackgroundRoker,也需要修改主线程上的控件。@Groo in public main window()(double)(i/BlendedImage.Width)是一个标准的C#bug,它总是生成0。你必须要求浮点除法,((double)i/BlendedImage.Width)@Adrian那么改变像素颜色后如何返回位图呢?我需要它在我的表单中显示它