Нужна помощь по проблеме в использовании c # .net 4.0 в режиме реального времени диаграммы в приложении Windows формы - PullRequest
0 голосов
/ 13 апреля 2011

У меня есть форма окна, в которой есть 1 кнопка (для простоты).

При нажатии этой кнопки я запускаю алгоритм в отдельном фоновом потоке, используя ParameterizedThreadStart.

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

  1. Если я инициализирую диаграмму в MainForm и передам этот объект в поток алгоритма, то он не разрешит и скажет распределение диаграммы идоступ к нему является многопоточным.

  2. Если у меня есть объект диаграммы внутри класса алгоритма, то тики диаграммы не отображаются.Отображается только пустая форма (это также выполняется с помощью _chart.Show ()), а галочки не отображаются.

Кроме того, как добавить точку на график, я использовал chart.Invoke (chart).AddPointDelegate, params) во втором случае, но он застревает в Invoke.

Пожалуйста, помогите мне с выходом.

РЕДАКТИРОВАТЬ:

    public MyForm()
    {
        InitializeComponent();

        _getChartDataDelegate = AddTickToChart;
    }

    public AddTickChartDelegate _getChartDataDelegate;

    public void AddTickToChart(ChartTickPoint point)
    {
        DateTime x = point.X;
        double y = point.Y;
        object[] parameters = { x, y };


        if (this.InvokeRequired)
        {// this prevents the invoke loop
            this.Invoke(new Action<ChartTickPoint>(_chart.chartDelegate), new object[] {  point }); // invoke call for _THIS_ function to execute on the UI thread
        }
        else
        {
            //function logic to actually add the datapoint goes here
            //_chart.Invoke(_chart.chartDelegate, parameters);
            _chart.AddTick(point);
        }
    }

    private void button_Click(object sender, EventArgs e)
    {
        Thread thread = new Thread(new ParameterizedThreadStart(MyUtils.RunAlgo));
        AlgoData algoData = new AlgoData(myFile, _getChartDataDelegate);
        thread.Start(algoData);
    }
    // MyForm ends

    // Intermediate static Util class to run algo
    MyUtils.RunAlgo(object obj)
    {
       // new Algo
       // Get delegate from algoData obj
       algo.Run(delegateInTheMyForm);

    }

    // Algo class's Run
    Run(AddTickChartDelegate delegateInTheMyForm)
    {
        delegateInTheMyForm(point);
    }

    // Chart class
    public AddTickChartDelegate chartDelegate;

    public void AddTick(ChartTickPoint point)
    {
        DateTime timeStamp = point.X;
        double y = point.Y;

        foreach (Series ptSeries in chart1.Series)
        {
            AddNewPoint(timeStamp, y, ptSeries);
        }
    }

Здесь я снова получаю проблему с несколькими потоками в this.Invoke (новое действие ..) в классе MyForm.

Далее,

If i replace this.Invoke(Action..) with chart.Invoke(..)
if (this.InvokeRequired)
{
_chart.Invoke(_chart.chartDelegate, point);
// instead of Action...
}

, затем он проходит, ноформа диаграммы не отвечает требованиям и является пустой.

1 Ответ

2 голосов
/ 13 апреля 2011

Напишите функцию для добавления точек данных в ваш класс формы

Например:

public void addDataPoint(YourDataClass entity)
{
    if(this.InvokeRequired)
    {// this prevents the invoke loop
       this.Invoke(new Action<YourDataClass>(addDataPoint),new object[]{entity}); // invoke call for _THIS_ function to execute on the UI thread
    }
    else{
       //function logic to actually add the datapoint goes here
       chartControl.Series[0].Points.AddXY(entity.X,entity.Y); // assuming your dataclass has the members X and Y and you are using the first Series on a MSChart control
    }
}

Вы можете вызвать эту функцию из вашего рабочего потока, так как она вызовет поток пользовательского интерфейса, чтобы избежать межпоточного доступа

Так что ... да, ваш работник должен иметь ссылку на эту функцию ... если вы хотите свести к минимуму знание своего класса алгоритма формы, вы можете создать объект, который содержит ссылку на форма (приведенная к ISynchronizedInvoke) и делегат (addDataPoint), поэтому работник остается отделенным от пользовательского интерфейса.

// РЕДАКТИРОВАТЬ: полный пример формы

using System;
using System.Windows.Forms;
using System.Threading;

namespace ExampleApplication
{
    public class Form1 : Form
    {

        #region designer-generated-code
        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
            System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
            System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
            this.chart1 = new System.Windows.Forms.DataVisualization.Charting.Chart();
            this.button1 = new System.Windows.Forms.Button();
            ((System.ComponentModel.ISupportInitialize)(this.chart1)).BeginInit();
            this.SuspendLayout();
            // 
            // chart1
            // 
            this.chart1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            chartArea1.Name = "ChartArea1";
            this.chart1.ChartAreas.Add(chartArea1);
            legend1.Name = "Legend1";
            this.chart1.Legends.Add(legend1);
            this.chart1.Location = new System.Drawing.Point(12, 12);
            this.chart1.Name = "chart1";
            series1.ChartArea = "ChartArea1";
            series1.Legend = "Legend1";
            series1.Name = "Series1";
            this.chart1.Series.Add(series1);
            this.chart1.Size = new System.Drawing.Size(733, 192);
            this.chart1.TabIndex = 0;
            this.chart1.Text = "chart1";
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(620, 210);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(125, 40);
            this.button1.TabIndex = 1;
            this.button1.Text = "button1";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(757, 262);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.chart1);
            this.Name = "Form1";
            this.Text = "Form1";
            ((System.ComponentModel.ISupportInitialize)(this.chart1)).EndInit();
            this.ResumeLayout(false);

        }

        private System.Windows.Forms.DataVisualization.Charting.Chart chart1;
        private System.Windows.Forms.Button button1;
        #endregion

        public Form1()
        {
            InitializeComponent();
        }

        public void AddDataPoint(myData d)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<myData>(this.AddDataPoint), new object[] { d });
            }
            else
            {
                chart1.Series[0].Points.AddXY(d.X, d.Y);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            new Thread(new ParameterizedThreadStart(worker)).Start(new Action<myData>(this.AddDataPoint));
        }
        private void worker(object obj)
        {
            var _delegate = (Action<myData>)obj;
            for (int x = 0; x < 50; x++)
            {
                _delegate(new myData { X = x, Y = 2 * x });
                Thread.Sleep(1000);
            }
        }
    }
    public class myData
    {
        public int X;
        public int Y;
    }
}
...