Need help on Problem in using c# .net 4.0 realtime chart in windows form application
I have a windows form which has 1 button (for simplicity).
On clicking this button, I start an algorithm in a separate background thread using ParameterizedThreadStart.
Now this algorithm produces output at regular time intervals which needs to be displayed in a chart.
If i init the chart in MainForm and pass this object to algorithm thread, then it doesnt allow and says chart's allocation and access are cross-thread.
If i have chart object inside algo class, then it doesnt display the chart ticks. Only a blank form shows up (that too by doing _chart.Show()) and no ticks displayed.
Also, how to AddPoint to the chart, I used chart.Invoke(chart.AddPointDelegate, params) in the 2nd case, but it gets stuck at Invoke.
Please help me with a way out.
EDIT:
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 _TH开发者_StackOverflowIS_ 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);
}
}
Here again i am getting cross-thread issue at this.Invoke(new Action..) in MyForm class.
Further,
If i replace this.Invoke(Action..) with chart.Invoke(..)
if (this.InvokeRequired)
{
_chart.Invoke(_chart.chartDelegate, point);
// instead of Action...
}
then it goes through , but the chart form is not responsive and is blank.
Write a function for adding datapoints in your form class
For example:
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
}
}
You can call this function from your worker thread since it will invoke the UI thread to avoid cross-thread access
So... yes, your worker will need to have a reference to that function... if you want to keep your algo class knowledge of the form to a minimum, you can build an object that holds the reference to the form (cast to ISynchronizedInvoke) and the delegate (addDataPoint) so the worker keeps separated from the UI.
//EDIT: Complete example Form
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;
}
}
精彩评论