Выполнение фонового процесса, который можно отменить с помощью кнопки Windows Form - PullRequest
0 голосов
/ 07 ноября 2019

Мне нужно запустить фоновый процесс (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 'доступен из потока, отличного от потока, в котором он был создан.

Я только начал работать с потоками, поэтомуможет быть, это действительно глупые вещи ...

...