将参数传递给backgroundWorker(用作取消按钮)
本文关键字:取消 按钮 参数传递 backgroundWorker | 更新日期: 2023-09-27 18:15:06
我是c#和面向对象编程的新手。我一直在尝试在我的GUI中实现一个"取消"按钮,以便用户可以在过程中停止它。
我读到这个问题:如何实现停止/取消按钮?并确定backgroundWorker对我来说应该是一个很好的选择,但是给出的示例并没有解释如何将参数传递给backgroundWorker。
我的问题是,我不知道如何传递一个参数到backgroundWorker,这样它就会停止进程;我只能让backgroundWorker停止自己。
我创建了以下代码来尝试学习这一点,我的表单有两个按钮(buttonStart和buttonStop)和一个backgroundWorker (backgroundWorkerStopCheck):
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;
using System.Timers;
namespace TestBackgroundWorker
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Set the background worker to allow the user to stop the process.
backgroundWorkerStopCheck.WorkerSupportsCancellation = true;
}
private System.Timers.Timer myTimer;
private void backgroundWorkerStopCheck_DoWork(object sender, DoWorkEventArgs e)
{
//If cancellation is pending, cancel work.
if (backgroundWorkerStopCheck.CancellationPending)
{
e.Cancel = true;
return;
}
}
private void buttonStart_Click(object sender, EventArgs e)
{
// Notify the backgroundWorker that the process is starting.
backgroundWorkerStopCheck.RunWorkerAsync();
LaunchCode();
}
private void buttonStop_Click(object sender, EventArgs e)
{
// Tell the backgroundWorker to stop process.
backgroundWorkerStopCheck.CancelAsync();
}
private void LaunchCode()
{
buttonStart.Enabled = false; // Disable the start button to show that the process is ongoing.
myTimer = new System.Timers.Timer(5000); // Waste five seconds.
myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);
myTimer.Enabled = true; // Start the timer.
}
void myTimer_Elapsed(object sender, ElapsedEventArgs e)
{
buttonStart.Enabled = true; // ReEnable the Start button to show that the process either finished or was cancelled.
}
}
}
代码,如果工作正常的话,在用户点击"开始"按钮之前,会在那里停留5秒钟,或者在用户点击"停止"按钮时,会迅速重新激活"开始"按钮。
这段代码有两个问题,我不确定如何处理:
1)"myTimer_Elapsed"方法在尝试启用Start按钮时导致InvalidOperationException,因为"跨线程操作无效"。如何避免跨线程操作?
2)现在backgroundWorker没有完成任何事情,因为我不知道如何为它提供参数,这样,当它被取消时,它将停止计时器。
我很感激任何帮助!
首先,避免"跨线程操作无效"的问题是在控件上使用Invoke。您不能使用来自其他线程的控件。
关于第二个问题,我将以如下方式实现。这是一个支持取消的最小后台worker实现。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication5
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Set the background worker to allow the user to stop the process.
backgroundWorkerStopCheck.WorkerSupportsCancellation = true;
backgroundWorkerStopCheck.DoWork += new DoWorkEventHandler(backgroundWorkerStopCheck_DoWork);
}
private void backgroundWorkerStopCheck_DoWork(object sender, DoWorkEventArgs e)
{
try
{
for (int i = 0; i < 50; i++)
{
if (backgroundWorkerStopCheck.CancellationPending)
{
// user cancel request
e.Cancel = true;
return;
}
System.Threading.Thread.Sleep(100);
}
}
finally
{
InvokeEnableStartButton();
}
}
private void buttonStart_Click(object sender, EventArgs e)
{
//disable start button before launch work
buttonStart.Enabled = false;
// start worker
backgroundWorkerStopCheck.RunWorkerAsync();
}
private void buttonStop_Click(object sender, EventArgs e)
{
// Tell the backgroundWorker to stop process.
backgroundWorkerStopCheck.CancelAsync();
}
private void InvokeEnableStartButton()
{
// this method is called from a thread,
// we need to Invoke to avoid "cross thread exception"
if (this.InvokeRequired)
{
this.Invoke(new EnableStartButtonDelegate(EnableStartButton));
}
else
{
EnableStartButton();
}
}
private void EnableStartButton()
{
buttonStart.Enabled = true;
}
}
internal delegate void EnableStartButtonDelegate();
}
关于向worker传递参数,您可以在RunWorkerAsync()
方法中传递任何对象,并在backgroundWorkerStopCheck_DoWork
方法中接收:
...
backgroundWorkerStopCheck.RunWorkerAsync("hello");
...
private void backgroundWorkerStopCheck_DoWork(object sender, DoWorkEventArgs e)
{
string argument = e.Argument as string;
// argument value is "hello"
...
}
希望能有所帮助。
试试这个例子,你会看到如何从BackgroundWorker传入和传入数据:
public partial class Form1 : Form
{
BackgroundWorker bw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.WorkerSupportsCancellation = true;
}
private void button1_Click(object sender, EventArgs e)
{
btnStart.Enabled = false;
btnCancel.Enabled = true;
double[] data = new double[1000000];
Random r = new Random();
for (int i = 0; i < data.Length; i++)
data[i] = r.NextDouble();
bw.RunWorkerAsync(data);
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btnStart.Enabled = true;
btnCancel.Enabled = false;
if (!e.Cancelled)
{
double result = (double)e.Result;
MessageBox.Show(result.ToString());
}
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
double[] data = (double[])e.Argument;
for (int j = 0; j < 200; j++)
{
double result = 0;
for (int i = 0; i < data.Length; i++)
{
if (bw.CancellationPending)
{
e.Cancel = true;
return;
}
result += data[i];
}
e.Result = result;
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
bw.CancelAsync();
btnStart.Enabled = true;
btnCancel.Enabled = false;
}
}