Forum

Пожалуйста or Регистрация для создания сообщений и тем.

Работа с BackgroundWorker

На форме табконтрол с 2 вкладками. На первой вкладке нужно выводить 2 графика, на другой - числовые результаты. При этом каждая точка графика рисуется через интервал Sleep, графики нужно через интервал Refresh chart обновлять (менять крайнее левое значение), через заданное время числовые данные записывать в файл Result.txt. Код программы:

Код

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace CsTest

{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        List<string> listResult = new List<string>();
        int numCharts = 2;
        bool ChartRefresh = false;
        private void SetCharts(Chart chart)
        {
            chart.BorderlineColor = Color.White;
            chart.BorderlineDashStyle = ChartDashStyle.Solid;
            chart.BackColor = Color.White;
            chart.BorderlineDashStyle = ChartDashStyle.Solid;
            chart.BorderlineWidth = 5;
            chart.BorderWidth = 2;
            chart.BorderDashStyle = ChartDashStyle.Solid;
            chart.BackColor = Color.White;
            chart.BorderColor = Color.Black;
            chart.BorderDashStyle = ChartDashStyle.Solid;
            chart.ChartAreas[0].AxisX.LabelStyle.Format = "F1";
            chart.ChartAreas[0].AxisY.LabelStyle.Format = "F1";
            chart.ChartAreas[0].AxisX.MajorGrid.LineColor = Color.Black;
            chart.ChartAreas[0].AxisY.MajorGrid.LineColor = Color.Black;
            chart.Series[0].ChartType = SeriesChartType.Line;
            chart.Series[0].MarkerSize = 7;
            chart.Series[0].Color = Color.Red;
            chart.Series[0].BorderWidth = 5;
        }
        private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            ShowResult();
        }
        private void ShowResult() // HACK ShowResult
        {
            string NameFileForWrite = "Result.txt";
            int nSleep = (int)(1000m * nudPeriodRead.Value);
            double stepX = (double)nudPeriodRead.Value;
            long nWriteFile = (long)(60.0 * (double)nudPeriodWriteFile.Value / (double)stepX);
            long nRefresh = (long)(nudPeriodRefresh.Value / nudPeriodRead.Value); // 
            double x = 0.0;
            double[] res = new double[numCharts];
            double min = 1.0;
            long stepWriteFile = 0;
            long stepRefreshChart = 0;
            while (!backgroundWorker1.CancellationPending)
            {
                string str = "";
                for (int i = 0; i < numCharts; i++)
                {
                    if (i == 0)
                        res[i] = min;
                    else
                        res[i] = 2.0 * res[i - 1];
                    str += ";" + String.Format("{0,10:F3}", res[i]);
                } // for
                str = String.Format("{0,10:F1}", x) + str;
                listResult.Add(str);
                str += "\n";
                if (stepRefreshChart == nRefresh)
                {
                    ChartRefresh = true;
                    stepRefreshChart = 0;
                }
                backgroundWorker1.ReportProgress(0, new ProgressDataMsec { Info = str, Data = res, X = x });
                if (stepWriteFile == nWriteFile)
                {
                    File.AppendAllLines(NameFileForWrite, listResult, Encoding.Default);
                    listResult.Clear();
                    stepWriteFile = 0;
                }
                Thread.Sleep(nSleep);
                x += stepX;
                stepWriteFile++;
                stepRefreshChart++;
                ChartRefresh = false;
            } //while
        }
        private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) // HACK ProgressChanged
        {
            ProgressDataMsec pData = e.UserState as ProgressDataMsec;
            rtbResult.AppendText(pData.Info);
            if (ChartRefresh)
            {
                double refresh = pData.X;
                chart1.ChartAreas[0].AxisX.Minimum = refresh;
                chart2.ChartAreas[0].AxisX.Minimum = refresh;
                File.AppendAllText("Test.txt", "\n" + refresh.ToString() + "\n", Encoding.Default);
            } // if
            else
            {
                chart1.Series[0].Points.AddXY(pData.X, pData.Data[0]);
                chart2.Series[0].Points.AddXY(pData.X, pData.Data[1]);
            } // else
        } // backgroundWorker1_ProgressChanged
        private void Form1_Load(object sender, EventArgs e)
        {
            SetCharts(chart1);
            SetCharts(chart2);
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }
        private void btnStop_Click(object sender, EventArgs e)
        {
            backgroundWorker1.CancelAsync();
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            backgroundWorker1.CancelAsync();
            Thread.Sleep(1000);
        }

    } // class 


    class ProgressDataMsec

    {

        public string Info { get; set; }

        public double[] Data { get; set; }

        public double X { get; set; }

    }


} // namespace


У меня возникли следующие проблемы:
1. Возникает исключение "System.InvalidOperationException: 'Axis Object - The minimum value of the axis is greater than the largest data point value." на 270 секунде, как я понимаю из-за неправильного обновления графиков.
2. При выходе из программы получаю исключение "System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation. Inner Exception. ObjectDisposedException: Cannot access a disposed object. Object name: 'RichTextBox'". Как я понимаю, при выходе ресурсы RichTextBox освобождаются, но к нему есть обращение.
Как исправить ошибки я не знаю, первый раз работаю с BackgroundWorker.Подскажите, пожалуйста, как исправить код программы. Проект https://disk.yandex.ru/d/FjLSEluIBxOONw

Добрый вечер 🖐
1. Стоит поставить Visual Studio на русском языке, ибо в ошибке ясно написано, что проблема не в коде обновления, а в том, что Вы вышли из допустимого диапазона.
2. Про BackgroundWorker было видео. Однако, рекомендую переходить к изучению потоков. Можете в принципе начать сначала, потому что вторая ошибка говорит о том, что идёт обращение к объекту, который Вы успешно Dispose. Не понятно где, но скорее всего это вытворяет сам BackgroundWorker, такого бы не было, выполняй Вы всё async в Task. Тот же Thread.Sleep() морозит весь UI, когда Task выполняется, не замораживая интерфейс. Об этом также рассказано в Уроках.

Добрый вечер, Хачатур!
Спасибо за ответ. Я тексты по программированию на английском читаю нормально, на английском практически не говорю. Так что я понял, в чем первая ошибка. Попробую поподробнее объяснить, что у меня не получается.
1. Я все уроки внимательно просмотрел раньше, наверное, нужно еще раз просмотреть. Я попробовал эту задачу решить с помощью async, но у меня ничего не получилось. Потом наткнулся на Ваше видео по BackgroundWorker, решил попробовать. Его использование позволило достаточно просто создавать и обновлять контролы на форме, не знаю, могут ли другие средства создания многопоточности так же просто решать эти задачи. Если бы не ошибки, то этого средства мне бы вполне хватило для реализации задач, в которых выполняются длительные операции. 
2. По-моему, дело не в языке Visual Studio. Я пробовал на русской VS, у меня возникали те же ошибки. Причем ошибка возникает на 30-й секунде. Программа работала нормально, когда Sleep была int,  работала при 1 секунде и более, никаких вылетов не было. Как только я попытался сделать 0.1 секунду - появилась ошибка при обновлении графиков. Исходя из этого я сделал вывод, что идет какой-то параллельный процесс, который вместо минимального значения диапазона при обновлении присваивает значение, большее значениям, которые должны отображаться на графике. Если отключить обновление, то ошибка исчезает, но мне нужно именно обновлять диапазоны графиков. Как исправить эту ошибку - я не знаю. 
3. Хотелось бы найти пример реализации многопоточности, который бы при выполнении длительной операции не только позволял нажимать кнопку и менять текст в метке, но и обновлял графики и выводил меняющиеся числовые (строковые) значения на разных вкладках. Это позволило бы лучше понять способы программирования многопоточных программ, которые обновляют разные контролы на форме. Думаю, не я один хотел бы посмотреть такие реализации с использованием async.
Спасибо Вам за уроки и надеюсь на Вашу помощь.
С уважением, Алексей