0

My Form contains a button and a chart added as shown below. enter image description here

My code is built such that a separate thread continuously gets data from the sender (which is being sent using the UDP protocol of communication), processes it and adds it to the global GLineSeries object 'gls'. GLineSeries is basically a class of the library which is basically just a list of the datapoints of the graph. My aim is that when the button is clicked this series is added to the chart in the form (cartesianChart1) and the plot shows. This is done using the line cartesianChart1.Series.Add(gls); The code for this is shown below (Form1.cs file)

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using LiveCharts;
using LiveCharts.WinForms;
using LiveCharts.Wpf;
using LiveCharts.Defaults;
using LiveCharts.Geared;
using System.Windows.Shell;

namespace livecharts_example
{
    public partial class Form1 : Form
    {
        LiveCharts.WinForms.CartesianChart cartesianChart1 = new LiveCharts.WinForms.CartesianChart();
        GLineSeries gls;
        Thread t;
        public Form1()
        {
            InitializeComponent();
            cartesianChart1.Dock = DockStyle.Fill;
            this.Controls.Add(cartesianChart1);            
            t = new Thread(() => {
            UdpClient dataUdpClient = new UdpClient(90);
            string carIP = "127.0.0.1";
            IPEndPoint carIpEndPoint = new IPEndPoint(IPAddress.Parse(carIP), 0);
            Byte[] receiveBytes;
            gls = new GLineSeries();
            gls.Values = new GearedValues<ObservablePoint>();
            while (true)
            {
                receiveBytes = dataUdpClient.Receive(ref carIpEndPoint);
                ObservablePoint op = new ObservablePoint(BitConverter.ToInt32(receiveBytes, 0), BitConverter.ToSingle(receiveBytes, 8));
                gls.Values.Add(op);
            }
        });
            t.SetApartmentState(ApartmentState.STA);
            t.Start();
    }

        private void button1_Click(object sender, EventArgs e)
        {
            cartesianChart1.Series.Add(gls);
        }
    }
}

The problem is that when the button is pressed the program jumps to the program.cs file and throws the error as shown below. I also tried aborting the thread 't' and then adding the lineseries to the chart but the error still arises. Can someone please help? enter image description here

Angad Khurana
  • 219
  • 1
  • 2
  • 5
  • why do you create `gls = new GLineSeries();` in a parallel thread? you could simply do it in the constructor on the main thread. – Mong Zhu Aug 05 '21 at 12:14
  • Well, the `GLineSeries` is being used from two different threads. UI-classes should only be used from the UI thread, so you need to transfer the points to the UI thread in one way or another. – JonasH Aug 05 '21 at 12:19
  • I guess you could use invoke here to drag the object onto the main thread. But I think it would suffice, if you simply take a normal list to collect your values in the background thread. And simply fill those values from the list into the chart series when the button is pressed. Remove the creation of the ui control elements from the background thread – Mong Zhu Aug 05 '21 at 12:24
  • Does this answer your question? [The calling thread cannot access this object because a different thread owns it](https://stackoverflow.com/questions/9732709/the-calling-thread-cannot-access-this-object-because-a-different-thread-owns-it) – asaf92 Aug 05 '21 at 12:50

1 Answers1

0

The following code worked. Thanks for all the suggestions

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using LiveCharts;
using LiveCharts.WinForms;
using LiveCharts.Wpf;
using LiveCharts.Defaults;
using LiveCharts.Geared;
using System.Windows.Shell;
using System.Windows;
using System.Collections.ObjectModel;

namespace livecharts_example
{
    public partial class Form1 : Form
    {
        LiveCharts.WinForms.CartesianChart cartesianChart1 = new LiveCharts.WinForms.CartesianChart();
        Thread t;
        static GLineSeries gls;
        public Form1()
        {
            InitializeComponent();
            cartesianChart1.Dock = DockStyle.Fill;
            this.Controls.Add(cartesianChart1);
            t = new Thread(() => {
            UdpClient dataUdpClient = new UdpClient(90);
            string carIP = "127.0.0.1";
            IPEndPoint carIpEndPoint = new IPEndPoint(IPAddress.Parse(carIP), 0);
            Byte[] receiveBytes;
                cartesianChart1.Invoke(new Action(() =>
                {
                    Form1.gls = new GLineSeries(); Form1.gls.Values = new GearedValues<ObservablePoint>();
                }));
                while (true)
            {
                receiveBytes = dataUdpClient.Receive(ref carIpEndPoint);
                ObservablePoint op = new ObservablePoint(BitConverter.ToInt32(receiveBytes, 0), BitConverter.ToSingle(receiveBytes, 8));
                    cartesianChart1.Invoke(new Action(() => {
                        gls.Values.Add(op);
                    }));
                }
            });
            t.SetApartmentState(ApartmentState.STA);
            t.Start();
         }
        private void button1_Click(object sender, EventArgs e)
        {
            cartesianChart1.Invoke(new Action(()=> {
                cartesianChart1.Series.Add(gls);
            }));
        }
    }
}

Angad Khurana
  • 219
  • 1
  • 2
  • 5