问题描述
我正在使用WinForms C#.NET 4.6
我有3种表格。 Main,Form1和Form2每个窗体都在不同的线程上运行。 Form1和Form2具有Arction LightningChart控件。每个这些Forms都有一个名为“ PlotUpdate”的方法,用于使用随机值更新图表。
主窗体具有一个计时器,该计时器每100毫秒触发一次。我想从Main Timer的滴答事件中调用PlotUpdate来更新Form1和Form2上的图表。如果将Arction LightningChart控件放置在“主窗体”中,则PlotUpdate方法有效,否则不起作用。
我该如何实现?
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相似
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();
}
}
}
解决方法
您在正确的轨道上。代码
// 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);
行
这不是创建Multiple UI threads in WinForms的唯一方法。
现在有关LightningChart控件/组件。与大多数UI控件一样,应在主线程中更新LightningChart(R).NET。在应用程序中使用另一个(后台)线程时,该线程的所有UI更新都必须通过Invoke(WinForms中的Control.Invoke())进行。 已经有WPF解决方案Multiple LightningChart and 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方法。