简体   繁体   English

C#图表轴标签未正确格式化

[英]C# Chart Axis Labels Not Formatting Properly

Assume we have a method call that accesses a remote database, taking approximately 1 second to complete and returning a DataTable (simulated below): 假设我们有一个访问远程数据库的方法调用,大约需要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;
}

The DataTable returned from this method is used to populate a Chart with a single line series. 从此方法返回的DataTable用于使用单个行系列填充Chart Why is it that this code shows correct, properly-formatted DateTime X-Axis labels: 为什么此代码显示正确,格式正确的DateTime X-Axis标签:

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

带有DateTime X轴的图表

and this code shows incorrect, unformatted X-Axis labels? 这段代码显示错误的,未格式化的X轴标签?

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

带有破X轴的图表

Note that removing the Thread.Sleep() call also fixes this issue, even using the second version. 请注意,即使使用第二个版本,删除Thread.Sleep()调用也可以解决此问题。

Answer lies in chart.Series[0].XValueType 答案在于chart.Series[0].XValueType

First, couple of statements: 首先,几个陈述:

  1. XValueType is Auto by default, and, if it is not specified explicitly, being resolved to specific type somewhere before Paint event. XValueType默认为Auto ,如果未明确指定,则在Paint事件之前解析为特定类型。

    It is not something obvious, I found it through decompiling sources; 这不是显而易见的事情,我通过反编译来源找到它; if you do want to follow my research, here are some milestones on the way: 如果你想跟随我的研究,这里有一些里程碑:

    • Chart constructor: Chart构造函数:

      this._dataManager.Initialize();

    • DataManager.Initialize : DataManager.Initialize

      chartImage.BeforePaint += ChartPicture_BeforePaint

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

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

  2. DataBind will try to resolve Auto to specific type based on DataSource . DataBind将尝试基于DataSourceAuto解析为特定类型。 If it is not Auto , it will not respect data type in DataSource . 如果它不是 Auto ,则不会尊重DataSource数据类型。

Ok, so what's happening in your sample: 好的,你的样本中发生了什么:

  1. When you don't use task, whole body of Form_Load executes synchronously; 当你不使用任务时, Form_Load整个主体同步执行; when you call DataBind on chart, it has Auto for XValueType and it is resolved to DateTime based on provide DataSource . 当您在图表上调用DataBind时,它具有Auto for XValueType并且基于提供DataSource将其解析为DateTime

  2. When you do use task with sleep, Paint event occurs before you initialize DataSource , which resolves XValueType to Double . 当您使用sleep with sleep时,在初始化DataSource之前会发生Paint事件,这XValueType解析为Double When after that you bind DataSource, it uses float representation of DateTime . 在此之后,您绑定DataSource,它使用DateTime浮点表示。

How to fix all that mess? 如何解决所有混乱局面? A lot of ways, but all of them based on chart value type: 有很多方法,但所有方法都基于图表值类型:

  • Specify value type explicitly in Form_Load Form_Load显式指定值类型
  • Remove series and add new one exactly before DataBind 删除系列并在DataBind之前添加新系列
  • Specify value type explicitly before DataBind DataBind之前显式指定值类型
  • ... ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM