2017-03-17 55 views
3

假設我們有訪問遠程數據庫中的一個方法調用,以大約1秒,完成並返回一個DataTable(模擬下面):C#圖表軸標籤未格式化正確

DataTable GetData() 
{ 
    Thread.Sleep(1000); // simulated delay 

    var dt = new DataTable("DataTable"); 
    dt.Columns.Add("DateTime", typeof(DateTime)); 
    dt.Columns.Add("Value", typeof(double)); 

    var rand = new Random(); 
    var date = new DateTime(2016, 1, 1); 
    for (int i = 0; i < 1000; i++) 
    { 
     dt.Rows.Add(date, rand.NextDouble() * 100); 

     date = date.AddHours(12); 
    } 

    return dt; 
} 

的數據表從該方法返回用於用單行系列填充Chart。爲什麼這個代碼顯示正確,正確格式的日期時間x軸標籤:

async void MainForm_Load(object sender, EventArgs e) 
{ 
    var data = GetData(); 
    chart.DataSource = data; 
    chart.DataBind(); 
} 

Chart with DateTime X-Axis

和驗證碼顯示不正確,未格式化的X軸標籤?

async void MainForm_Load(object sender, EventArgs e) 
{ 
    var data = await Task.Run(() => GetData()); 
    chart.DataSource = data; 
    chart.DataBind(); 
} 

Chart with broken X-Axis

注意去除Thread.Sleep()調用也修正了這個問題,即使使用第二個版本。

回答

1

答案就在chart.Series[0].XValueType

首先,情侶聲明:

  1. XValueTypeAuto默認情況下,如果沒有在什麼地方Paint事件明確指定,解析爲特定的類型。

    這不是很明顯,我通過反編譯源找到它;如果你想跟着我的研究,這裏有在途中的一些里程碑:

    • Chart構造:

      this._dataManager.Initialize();

    • DataManager.Initialize

      chartImage.BeforePaint += ChartPicture_BeforePaint

    • DataManager.ChartPicture_BeforePaint
    • DataManager.PrepareData
    • Series.PrepareData =>

      if (this._xValueType == ChartValueType.Auto) { this._xValueType = ChartValueType.Double;

  2. DataBind將盡力解決Auto基於DataSource特定類型。如果它是而不是Auto,它將不會遵守DataSource中的數據類型。

好了,發生了什麼你的樣品中:

  1. 當你不使用任務的全身同步執行;當您在圖表上呼叫DataBind時,它的AutoXValueType,根據DataSource的提供,它將被解析爲DateTime

  2. 當你使用任務的睡眠,你初始化DataSource,解決XValueTypeDouble之前發生Paint事件。在綁定DataSource之後,它使用DateTime的浮點表示形式。

如何解決所有這些混亂?方法很多,但基於圖表的值類型所有的人:

  • 明確指定
  • 值類型刪除系列,並添加新的恰好之前DataBind
  • 之前顯式指定的值類型DataBind
  • ...