2017-03-17 3 views
3

Angenommen wir einen Methodenaufruf haben, die eine Remote-Datenbank zugreift, ca. 1 Sekunde unter abzuschließen und eine DataTable (simuliert unten) Rückkehr:C# Diagramm Achsenbeschriftungen nicht ordnungsgemäß Formatierung

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; 
} 

Die Datentabelle von dieser Methode zurück wird verwendet, um eine Chart mit einer einzelnen Zeilenserie zu füllen. Warum ist es, dass dieser Code korrekt zeigt, korrekt formatierte Datetime X-Achsenbeschriftungen:

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

Chart with DateTime X-Axis

und dieser Code zeigt falsche, unformatierte X-Achsen-Etiketten?

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

Chart with broken X-Axis

Beachten Sie, dass die Thread.Sleep() Anruf zu entfernen auch dieses Problem behebt, auch die zweite Version.

Antwort

1

Antwort liegt in chart.Series[0].XValueType

Zuerst paar Erklärungen:

  1. XValueType ist Auto standardmäßig, und wenn es nicht explizit angegeben ist, irgendwo vor Paint Veranstaltung auf bestimmte Art gelöst werden.

    Es ist nicht etwas Offensichtliches, ich fand es durch Dekompilieren von Quellen; wenn Sie nicht wollen, meine Forschung zu folgen, sind hier einige Meilensteine ​​auf dem Weg:

    • Chart Konstruktor:

      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 werden versuchen Auto auf bestimmte Art auf DataSource Basis zu lösen. Wenn es nichtAuto ist, wird es den Datentyp in nicht respektieren.

Ok, so was in der Probe passiert:

  1. Wenn Sie nicht Aufgabe verwenden, ganze Körper führt synchron; Wenn Sie DataBind auf Diagramm anrufen, hat es Auto für XValueType und es wird zu DateTime basierend auf DataSource aufgelöst.

  2. Wenn Sie Aufgabe tun verwenden mit Schlaf tritt Paint Ereignis, bevor Sie DataSource initialisieren, die XValueType zu Double löst. Wenn Sie anschließend DataSource binden, verwendet es die Gleitkommadarstellung DateTime.

Wie zu beheben all diese Unordnung? Viele Möglichkeiten, aber alle von ihnen basierend auf den Diagrammwerttyp:

  • Werttyp in
  • explizit angeben Serie entfernen und neue hinzufügen genau vor DataBind
  • Werttyp explizit angeben, bevor DataBind
  • ...