我需要启动一个后台进程(Solver),该进程从我的主窗体(Form1)接收数据并在ProgressBar中以新窗体(FormStatus)指示其进度。我决定从Form1启动FormStatus,然后从FormStatus的OnLoad启动,以在单独的线程中执行规划求解过程。在求解器执行的任何时候,我都可以使用FormStatus中的ButtonStop中止它。如果直接启动,该过程将阻止该表单。
如果进程被按钮终止,则抛出异常,否则(如果计算完成),求解器返回空字符串并关闭FormStatus。
主要Form1的代码:
using System;
using System.Windows.Forms;
namespace CS_Threads
{
public partial class Form1 : Form
{
// Contains some data
public class CData
{ public int Int { set; get; } }
private CData data;
public Form1()
{
InitializeComponent();
data = new CData() { Int = 100 };
}
// On ButtonGO press open FormStatus to start the solver
private void ButtonGO_Click(object sender,EventArgs e)
{
int result;
using (FormStatus f = new FormStatus(data))
{
f.ShowDialog();
result = f.Result;
}
// Fill the RTBox according to calculation results
if (result < 0) RTBox.Text = "Failed";
else RTBox.Text = "Success";
}
}
}
FormStatus的代码:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CS_Threads
{
public partial class FormStatus : Form
{
private Form1.CData data;
private CancellationTokenSource source;
public int Result { private set; get; }
public FormStatus(Form1.CData d)
{
InitializeComponent();
data = d; // Didn't find a better way to pass the class reference. Maybe make this member public in Form1?
Result = -1; // Default value of Result if form was closed or process terminated
source = new CancellationTokenSource();
}
// On ButtonStop press stop the Solver and close form
private void ButtonStop_Click(object sender,EventArgs e)
{
source.Cancel();
Close();
}
// On form load launch Solver: Warning CS1998 This async method lacks 'await' operators and will run synchronously.Consider using the 'await' operator...
private async void FormStatus_Load(object sender,EventArgs e)
{
Task<string> t = Task.Run(() => Solver(data,this,source.Token));
string res = t.Result;
}
// Solver: Same warning CS1998
private static async Task<string> Solver(Form1.CData data,FormStatus f,CancellationToken ct)
{
try
{
// Do some calculations
long max = 1000;
for (long i = 0; i < max && !ct.IsCancellationRequested; i++)
for (long j = 0; j < max && !ct.IsCancellationRequested; j++)
{
data.Int = 10;
f.ProgressBar.Value = (int)(((double)i / (double)max) * ((double)j / (double)max) * 100.0);
}
if (!ct.IsCancellationRequested)
{
f.Result = 0;
f.Close();
}
else throw new Exception("Task has been cancelled");
}
catch (Exception ex)
{ return ex.ToString(); }
return null;
}
}
}
目前,我在FormStatus中有两个警告,并且该过程在Solver的第一次迭代中终止,并在'string res'中引发异常:System.InvalidOperationException:跨线程操作无效:从其他线程访问的控件'ProgressBar'比创建它的线程要多。
我刚刚开始使用线程,所以可能会有一些非常愚蠢的东西...