假设我们有一个访问远程数据库的方法调用,大约需要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();
}


c# - C#图表轴标签格式不正确-LMLPHP

并且此代码显示了不正确的,未格式化的X轴标签?

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


c# - C#图表轴标签格式不正确-LMLPHP

请注意,即使使用第二个版本,删除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
当您将任务与睡眠一起使用时,在初始化Paint之前会发生DataSource事件,这会将XValueType解析为Double。之后,绑定数据源时,它将使用DateTime的浮点表示形式。


如何解决所有问题?有很多方法,但是所有方法都基于图表值类型:


Form_Load中显式指定值类型
删除系列并在DataBind之前添加一个新系列
DataBind之前显式指定值类型
...

关于c# - C#图表轴标签格式不正确,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42858654/

10-12 15:51