假设我们有一个访问远程数据库的方法调用,大约需要 1 秒完成并返回一个 DataTable
(下面模拟):
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;
}
从此方法返回的 DataTable 用于用单行系列填充 Chart
。为什么此代码显示正确、格式正确的 DateTime X 轴标签:
async void MainForm_Load(object sender, EventArgs e)
{
var data = GetData();
chart.DataSource = data;
chart.DataBind();
}
并且这段代码显示了不正确的、未格式化的 X 轴标签?
async void MainForm_Load(object sender, EventArgs e)
{
var data = await Task.Run(() => GetData());
chart.DataSource = data;
chart.DataBind();
}
请注意,删除 Thread.Sleep()
调用也可以解决此问题,即使使用第二个版本也是如此。
最佳答案
答案就在chart.Series[0].XValueType
首先,声明几个:
XValueType
是Auto
默认情况下,如果未明确指定,则在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;
-
DataBind
将尝试解决Auto
到基于DataSource
的特定类型.如果它不是Auto
, 它不会考虑DataSource
中的数据类型.
好的,那么您的示例中发生了什么:
当你不使用任务时,
Form_Load
的整体同步执行;当你调用DataBind
在图表上,它有Auto
对于XValueType
并解析为DateTime
基于提供DataSource
.当你在 sleep 中使用任务时,
Paint
事件发生在你初始化之前DataSource
,它解决了XValueType
至Double
.之后绑定(bind) DataSource 时,它使用DateTime
的浮点表示.
如何解决所有这些乱七八糟的问题?很多方法,但都是基于图表值类型:
- 在
Form_Load
中明确指定值类型 - 删除系列并恰好在
DataBind
之前添加新系列 - 在
DataBind
之前明确指定值类型 - ...
关于C# 图表轴标签格式不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42858654/