0

I am using WinForms C# .NET 4.6

I have 3 Forms. Main, Form1 and Form2 Each form is running on a different thread. Form1 and Form2 have Arction LightningChart Control.. Each of those Forms has a method called "PlotUpdate" to update the charts with random values.

The Main Form has a timer that is triggered every 100ms. I want to call PlotUpdate from the Main Timer tick event to update the charts on Form1 and Form2. PlotUpdate method works in case the Arction LightningChart Control is placed in the Main Form, otherwise it doesn't.

How can I achieve this?

MainForm.cs

using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;

namespace MultipleUIThreads
{
    public partial class MainForm : Form
    {
        const int FormSeriesCount = 3;
        static System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();

        public MainForm()
        {
            InitializeComponent();

            myTimer.Interval = 100;
            myTimer.Tick += myTimer_Tick;
            myTimer.Start();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

            // Start new UI thread for Form3
            Thread thread1 = new Thread(() =>
            {
                Form1 f1 = new Form1();
                Application.Run(f1);
            });
            thread1.Start();

            // Start new UI thread for Form2
            Thread thread2 = new Thread(() =>
            {
                Form2 f2 = new Form2(); 
                Application.Run(f2);
            });
            thread2.Start();

        }

        private void myTimer_Tick(object sender, EventArgs e)
        {
            //What shall I write here
        }
    }
}

Form1.cs / Form2.cs are alike

using System;
using System.Windows.Forms;
using Arction.WinForms.Charting;

namespace MultipleUIThreads
{
    public partial class Form1 : Form
    {

        int _pointsAdded = 0;
        Random _rand = new Random();
        public Form1()
        {
            InitializeComponent();
            ChartCreator.InitChart(LChart);

        }

        public void PlotUpdate()
        {
            LChart.BeginUpdate();

            double x = _pointsAdded * 0.1;
            for (int i = 0; i < 1; i++)
            {
                SeriesPoint[] points = new SeriesPoint[1];
                points[0].X = x;
                points[0].Y = _rand.Next(-100, 100);
                LChart.ViewXY.PointLineSeries[i].AddPoints(points, false);
            }

            LChart.ViewXY.XAxes[0].ScrollPosition = x;
            LChart.EndUpdate();

            _pointsAdded++;
        }
    }
}

ChartCreator.cs

using Arction.WinForms.Charting;
using Arction.WinForms.Charting.Axes;
using Arction.WinForms.Charting.SeriesXY;
using Arction.WinForms.Charting.Views.ViewXY;

namespace MultipleUIThreads
{
     class ChartCreator
    {
        public static void InitChart(LightningChartUltimate ulChart)
        {
            ulChart.BeginUpdate();
            ViewXY view = ulChart.ViewXY;

            AxisX xAxis = view.XAxes[0];
            xAxis.SetRange(0, 20);
            xAxis.ScrollMode = XAxisScrollMode.Scrolling;

            view.YAxes.Clear();

            for (int seriesIndex = 0; seriesIndex < 1; seriesIndex++)
            {
                AxisY yAxis = new AxisY(view);
                yAxis.SetRange(-100, 100);
                view.YAxes.Add(yAxis);

                PointLineSeries line = new PointLineSeries(view, xAxis, yAxis);
                line.PointsVisible = false;
                line.LineStyle.Color = DefaultColors.SeriesForBlackBackground[seriesIndex];
                view.PointLineSeries.Add(line);
            }

            view.DropOldSeriesData = true;
            view.AxisLayout.YAxesLayout = YAxesLayout.Stacked;


            ulChart.EndUpdate();

        }
    }
}
4

1 回答 1

0

你在正确的轨道上。编码

            // Start new UI thread for Form3
        Thread thread1 = new Thread(() =>
        {
            Form1 f1 = new Form1();
            Application.Run(f1);
        });
        thread1.Start();

将为您创建一个在其自己的线程上运行的 Windows 窗体。只是不要忘记 UI 线程应该作为 AppartmentState.STA 运行。因此,包含行thread1.SetApartmentState(ApartmentState.STA); 这不是在 WinForms 中创建多个 UI 线程的唯一方法。

现在介绍 LightningChart 控件/组件。LightningChart(R) .NET 应该在主线程中更新,就像大多数 UI 控件一样。在应用程序中使用另一个(后台)线程时,来自该线程的所有 UI 更新都必须通过 Invoke(WinForms 中的 Control.Invoke())。已经有 WPF 解决方案Multiple LightningChart 和 multiple UI threads。您的 WinForms 应用程序应该/可以遵循非常相似的逻辑。您需要的第一件事是您计划稍后操作/访问的图表列表。其次,不要忘记应该设置Chart.Parent,即Form本身或该表单中的Panel。最后,您为要在 Tick 处理程序中更新的每个 LightningChart 实例调用 Chart.Invoke()。例如,

    private void myTimer_Tick(object sender, EventArgs e)
    {
        if(_chartContainers.Count == 0)
        {
            for (int i = 0; i < _chartForms.Count; i++)
            {
                //ChartWindow cw = new ChartWindow(_chartForms[i]);
                _chartForms[i].Invoke((System.Action)delegate 
                {
                    ChartWindow cw = new ChartWindow(_chartForms[i]);
                    _chartContainers.Add(cw);
                });

            }
        }

        if (_chartForms.Count == 0)
            return;

        for (int iChart = 0; iChart < _chartForms.Count; iChart++)
        {
            ChartWindow cw = _chartContainers[iChart];
            cw.Chart.Invoke((System.Action)delegate 
            {
                cw.AddSeriesPoints(new double[] { random.NextDouble()*10 });
            });
        }
    }

第一部分实际上是使用(空)Form 的线程在其中创建 ChartWindow(基本上是创建 Chart 并将父级设置为特定的 Form)。

第二部分为每个图表添加新的随机点。在那里, ChartWindow 类中定义的AddSeriesPoints自定义方法用于添加点数组和滚动。您也可以直接使用 LightningChart 方法。

于 2020-11-04T15:38:49.510 回答