2011-04-13 84 views
0

我有一个窗体,其中有1个按钮(为简单起见)。需要帮助在Windows窗体应用程序中使用C#.net 4.0实时图表的问题

在点击这个按钮,我使用ParameterizedThreadStart在一个单独的后台线程启动的算法。

现在,这个算法在需要被显示在图表中固定的时间间隔产生输出。

  1. 如果我在初始化MainForm的图表,并通过此对象的算法线程,那么它不容许,并表示图表的分配和访问是跨线程。

  2. 如果我有ALGO类的内部图表对象,那么它不显示图表蜱。只显示一个空白表格(通过执行_chart.Show())并且不显示任何刻度。

此外,如何AddPoint到图表,我用chart.Invoke(chart.AddPointDelegate,则params)在第二种情况,但卡在调用。

请帮我一条出路。

编辑:

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); 
     } 
    } 

这里我再次在MyForm的类越来越善于this.Invoke(新动作..)跨线程问题。

此外,

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

然后它通过,但图表形式不响应并且是空的。

回答

2

写一个函数在你的窗体类

添加的数据点例如:

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 
    } 
} 

你可以从你的工作线程调用此功能,因为它会调用UI线程,以避免跨线程访问

所以......是的,你的工人将需要有该功能的参考...如果你想保持形式的算法中知识阶层到最低限度,你可以建立一个保存的对象引用表单(转换为ISynchronizedInvoke )和委托(addDataPoint),以便工作者与UI分离。

//编辑:完整的示例表格

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; 
    } 
} 
+0

所以我需要有工作线程(算法中类)内部窗体类的处理?第一块这个.Invoke(..)部分是什么意思? – 2011-04-13 16:49:31

+0

见编辑后 – DarkSquirrel42 2011-04-13 17:15:49

+0

为什么我们需要2个引用(表单和委托)?所以我只会将代表的参考传递给算法类。这个委托在Form类中定义,对吧?第一个this.invoke(new Action ..)在做什么? – 2011-04-13 17:31:36

相关问题