Мне нужно запустить фоновый процесс (Solver), который получает данные из моей главной формы (Form1) и отображает прогресс в ProgressBar в новой форме (FormStatus). Я решил запустить FormStatus из Form1, а затем OnLoad FormStatus, чтобы выполнить процесс Solver в отдельном потоке. В любое время выполнения Солвера я могу прервать его с помощью ButtonStop в FormStatus. При непосредственном запуске процесс блокирует форму.
Если процесс завершается нажатием кнопки, возникает исключение, в противном случае (если расчет завершен) Солвер возвращает нулевую строку и закрывает 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 'доступен из потока, отличного от потока, в котором он был создан.
Я только начал работать с потоками, поэтомуможет быть, это действительно глупые вещи ...