2011-04-13 85 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

相關問題