2017-03-17 59 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
  • ...