none
Problem bei CellDoubleClick mit maskedTextBox RRS feed

  • Frage

  • Hallo,

    ich habe auf meiner Benutzeroberfläche ein DataGridView-Objekt, worin ich alle Dateinamen eines bestimmten Verzeichnisses aufliste. Ein Doppelklick auf die entsprechende Zeile liest die Textdatei(*.txt) ein und stellt die beiden enthaltenen Temperaturverläufe in einem Chart grafisch da.

    Das Einlesen kann ein paar Sekunden dauern. Deshalb möchte ich über eine maskedTextBox ausgeben, ob das Programm gerade beschäftigt, oder bereit ist.

    Was passiert, ist aber folgendes: Meine Methode private void CellDoubleClick2(object sender, DataGridViewCellEventArgs e)
    wird inklusive des Lesevorgangs, aber exklusive der "busy"-Ausgabe abgearbeitet. Erst ganz am Ende, wo kein Befehl mehr in der Methode steht, werden die Ausgaben ausgeführt. (Getestet durch Debuggen mit Breakpoints)

    Das ist natürlich nicht sinngemäß, weil ich so nicht sehe, dass das Programm beschäftigt ist.

    Bei der private void button1_Click(object sender, EventArgs e) - Methode
    funktioniert die Busy-Ausgabe korrekt. ("busy" -> synchronisieren -> "ready")

    Hier der Programmausschnitt:

    private void CellDoubleClick2(object sender, DataGridViewCellEventArgs e)                                               // Local filenames: CellDoubleClick event: Plot file
            {
                maskedTextBox6.Text = "busy";
    
                livestream = false;                                                                                                 // Disable livestream (static graph)
                timeStamp.Clear();                                                                                                  // Clear timeStamp list
                timeStamp.TrimExcess();                                                                                             // Reset reserved memory
                temp1.Clear();                                                                                                      // Clear temp1 list
                temp1.TrimExcess();                                                                                                 // Reset reserved memory
                temp2.Clear();                                                                                                      // Clear temp2 list
                temp2.TrimExcess();                                                                                                 // Reset reserved memory
               String filename = dt2.Rows[e.RowIndex][0].ToString();                                                                // Get doubleclicked filename
                filename = filename.Replace("\r", "");                                                                              // Cut off additional return if it's there
                string path = "..\\..\\..\\..\\SDfiles";                                                                            // Set local files path
                using (var sr = new StreamReader(Path.Combine(path, filename)))                                                     // Combine path and filename, create StremReader
                {
                    string line;
                    // Current read line
                    while ((line = sr.ReadLine()) != null)                                                                          // Read until line is empty
                    {
                        string[] part = line.Split(' ');                                                                            // Split line by space
                        if (line.Length > 0)                                                                                        // If line has content
                        {
    
                            timeStamp.Add(Convert.ToDouble(part[0], new CultureInfo("en-US")));                                     // Convert unix timestamp to double and add it to timeStamp list
                            temp1.Add(Convert.ToDouble(part[1], new CultureInfo("en-US")));                                         // Convert temperature value of sensor1 to double and add it to temp1 list
                            temp2.Add(Convert.ToDouble(part[2], new CultureInfo("en-US")));                                         // Convert temperature value of sensor2 to double and add it to temp2 list
                        }
                    }
                }
                
                DateTime[] stampArray = new DateTime[timeStamp.Count];                                                              // Create stampArray with the same size as timeStap list
                int idx = 0;                                                                                                        // Initialize array index, set it to 0
                double max = Double.MinValue;   // max. time value in dataset                                                       // Initialize upper time limit and set it to the minimum (force overwrite)
                double min = Double.MaxValue;   // min. time value in dataset                                                       // Initialize lower time limit and set it to maximum (force overwrite)
                foreach (double stamp in timeStamp)                                                                                 // Repeat for every timeStamp value
                {
                    System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);                     // Create unix times reference DateTime
                    dtDateTime = dtDateTime.AddSeconds(stamp).ToUniversalTime();                                                    // Add unix timestamp
                    stampArray[idx] = dtDateTime;                                                                                   // Put calculated DateTime into array
                    idx++;
                    min = Math.Min(min, stamp);
                    max = Math.Max(max, stamp);
                }
                System.DateTime minTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
                minTime = minTime.AddSeconds(min).ToUniversalTime();
                System.DateTime maxTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
                maxTime = maxTime.AddSeconds(max).ToUniversalTime();
                maskedTextBox3.Text = minTime.ToString("dd.MM.yyyy");
                maskedTextBox5.Text = minTime.ToString("HH:mm:ss");
                maskedTextBox4.Text = maxTime.ToString("dd.MM.yyyy");
                maskedTextBox8.Text = maxTime.ToString("HH:mm:ss");
    
                setScale();
    
                chart1.Series["Temperature 1"].Points.DataBindXY(stampArray, temp1.ToArray());
                chart1.Series["Temperature 2"].Points.DataBindXY(stampArray, temp2.ToArray());
                graphLoaded = true;
                maskedTextBox6.Text = "ready";
            }

    Dienstag, 18. Dezember 2018 11:53

Antworten

  • Hi Marius,
    um wie viele Punkte in einer Serie handelt es sich? Ist es möglich, ohne wesentlichen Informationsverlust die Menge zu verringern (z.B. immer nur aus 5 Punkten einen Mittelwert darstellen)?

    Um welches Chart-Control handelt es sich? Gibt es für das Chart-Control Begin- und End-Edit Methoden o.ä., damit erst mit dem Zeichnen begonnen wird, wenn alle Daten zugewiesen wurden?


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Mittwoch, 19. Dezember 2018 09:17
  • SOLVED!

    Das Lesen und Anzeigen von Dateien dauert nun immer nur etwa eine Sekunde.

    Ich habe mich einfach mal auf 2000 Datenpunkte beschränkt. So sollte jeder Full-HD-Monitor gut bedient sein.

    Vielen Dank für die Hilfe und die Ideen.

    Falls der neue Code interessiert:

    private void CellDoubleClick2(object sender, DataGridViewCellEventArgs e)                                               // Local filenames: CellDoubleClick event: Plot file
            {
                maskedTextBox6.Text = "busy";
                maskedTextBox6.Invalidate();
                maskedTextBox6.Update();
                maskedTextBox6.Refresh();
                livestream = false;                                                                                                 // Disable livestream (static graph)
                timeStamp.Clear();                                                                                                  // Clear timeStamp list
                timeStamp.TrimExcess();                                                                                             // Reset reserved memory
                temp1.Clear();                                                                                                      // Clear temp1 list
                temp1.TrimExcess();                                                                                                 // Reset reserved memory
                temp2.Clear();                                                                                                      // Clear temp2 list
                temp2.TrimExcess();                                                                                                 // Reset reserved memory
               String filename = dt2.Rows[e.RowIndex][0].ToString();                                                                // Get doubleclicked filename
                filename = filename.Replace("\r", "");                                                                              // Cut off additional return if it's there
                string path = "..\\..\\..\\..\\SDfiles";                                                                            // Set local files path
                using (var sr = new StreamReader(Path.Combine(path, filename)))                                                     // Combine path and filename, create StremReader
                {
                    string line;
                    // Current read line
                    while ((line = sr.ReadLine()) != null)                                                                          // Read until line is empty
                    {
                        string[] part = line.Split(' ');                                                                            // Split line by space
                        if (line.Length > 0)                                                                                        // If line has content
                        {
    
                            timeStamp.Add(Convert.ToDouble(part[0], new CultureInfo("en-US")));                                     // Convert unix timestamp to double and add it to timeStamp list
                            temp1.Add(Convert.ToDouble(part[1], new CultureInfo("en-US")));                                         // Convert temperature value of sensor1 to double and add it to temp1 list
                            temp2.Add(Convert.ToDouble(part[2], new CultureInfo("en-US")));                                         // Convert temperature value of sensor2 to double and add it to temp2 list
                        }
                    }
                }
                
                DateTime[] stampArray = new DateTime[timeStamp.Count];                                                              // Create stampArray with the same size as timeStap list
                int idx = 0;                                                                                                        // Initialize array index, set it to 0
                double max = Double.MinValue;   // max. time value in dataset                                                       // Initialize upper time limit and set it to the minimum (force overwrite)
                double min = Double.MaxValue;   // min. time value in dataset                                                       // Initialize lower time limit and set it to maximum (force overwrite)
                foreach (double stamp in timeStamp)                                                                                 // Repeat for every timeStamp value
                {
                    System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);                     // Create unix times reference DateTime
                    dtDateTime = dtDateTime.AddSeconds(stamp).ToUniversalTime();                                                    // Add unix timestamp
                    stampArray[idx] = dtDateTime;                                                                                   // Put calculated DateTime into array
                    idx++;
                    min = Math.Min(min, stamp);
                    max = Math.Max(max, stamp);
                }
                System.DateTime minTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
                minTime = minTime.AddSeconds(min).ToUniversalTime();
                System.DateTime maxTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
                maxTime = maxTime.AddSeconds(max).ToUniversalTime();
                maskedTextBox3.Text = minTime.ToString("dd.MM.yyyy");
                maskedTextBox5.Text = minTime.ToString("HH:mm:ss");
                maskedTextBox4.Text = maxTime.ToString("dd.MM.yyyy");
                maskedTextBox8.Text = maxTime.ToString("HH:mm:ss");
    
                setScale();
    
                time.Clear();
                time.TrimExcess();
                graph1.Clear();
                graph1.TrimExcess();
                graph2.Clear();
                graph2.TrimExcess();
    
                int averageNumber = (int)Math.Round((double)(timeStamp.Count() / 2000), MidpointRounding.ToEven);
    
                Double[] tsArray = timeStamp.ToArray();
                Double[] t1Array = temp1.ToArray();
                Double[] t2Array = temp2.ToArray();
                double sSum = tsArray[0];
                double t1Sum = t1Array[0];
                double t2Sum = t2Array[0];
    
                for (int i = 1; i < tsArray.Length; i++)
                {
                    if ((i % (averageNumber)) == 0)
                    {
                        time.Add((sSum / averageNumber));
                        graph1.Add((t1Sum / averageNumber));
                        graph2.Add((t2Sum / averageNumber));
                        sSum = 0;
                        t1Sum = 0;
                        t2Sum = 0;
                    }
                    sSum += tsArray[i];
                    t1Sum += t1Array[i];
                    t2Sum += t2Array[i];
                }
                DateTime[] timeArray = new DateTime[time.Count];
                int index = 0;
                foreach (double stamp in time)
                {
                    System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
                    dtDateTime = dtDateTime.AddSeconds(stamp).ToUniversalTime();
                    timeArray[index] = dtDateTime;
                    index++;
                }
                chart1.Series["Temperature 1"].Points.DataBindXY(timeArray, graph1.ToArray());
                chart1.Series["Temperature 2"].Points.DataBindXY(timeArray, graph2.ToArray());
                graphLoaded = true;
                maskedTextBox6.Text = "ready";
            }

    Mittwoch, 19. Dezember 2018 10:37

Alle Antworten

  • Ein zweites Problem:

    Es ist zeitlich sehr relevant, ob ich eine Datei als Erstes über die CellCoubleClick-Methode anzeigen lasse, oder als Zweites.
    (Bei der gleichen Datei versteht sich)
    Rufe ich eine Datei direkt nach dem Programmstart auf, dauert es bis zur Anzeige etwa 2 Sekunden.
    Rufe ich die gleiche Datei nach einer anderen Datei auf, dauert die Anzeige etwa 10 Sekunden.
    In den Zeiträumen steht leider nicht "busy" im Textfeld und die CPU-Auslastung liegt in in der Zeit bei 25%.

    Ein paralleler Thread wird in der Zeit nicht weiter ausgeführt.
    (Die aktuellen Dateinamen des externen Temperatursensors sollten sekündlich seriell entgegengenommen werden)

    Ich habe schon das Zurücksetzen der Listen auskommentiert, was bei unterschiedlichen Dateilängen natürlich teilweise alte Werte beibehält, aber auch das ändert nichts an den Zeiten.


    • Bearbeitet Marius01010 Dienstag, 18. Dezember 2018 12:10
    Dienstag, 18. Dezember 2018 12:09
  • Hi Marius,
    ich kann nicht erkennen, dass in der Methode CellDoubleClick2 asynchron gearbeitet wird. Damit wird die Oberfläche erst aktualisiert, wenn die Methode vollständig abgearbeitet wurde. Deshalb ist da "busy" auch nicht zu sehen, da zum Zeitpunkt des Refreshs schon wieder "ready" drinsteht. Wenn das Lesen der Daten und die Anzeige länger als die geforderte sekündliche Aktualisierung dauert, musst Du Dir etwas mehr Gedanken machen. Ich denke da an eine Warteschlange und einen Thread, der die Warteschlageneinträge verarbeitet. Wenn die Verarbeitung stockt oder zu lange dauert, werden beim nächsten Durchlauf alle Warteschlangeneinträge bis auf den letzten gelöscht.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Dienstag, 18. Dezember 2018 12:23
  • Danke. Wie sorge ich dafür, dass die Methode asynchron arbeitet, so dass der neue Textbox-Text schon bei dem entsprechenden Befehl auf die GUI übernommen wird?

    Bzw. gibt es eine Möglichkeit, die Oberfläche zwischendurch schon manuell zu aktualisieren?
    • Bearbeitet Marius01010 Dienstag, 18. Dezember 2018 12:40
    Dienstag, 18. Dezember 2018 12:31
  • Hi Marius,
    für die asynchrone Arbeit gibt es verschiedene Klassen, z.B. Task oder Thread. Damit kann die Verarbeitung in einen anderen Thread ausgelagert werden und der UI-Thread hat "freie" Zeit, die Oberfläche zu aktualisieren. Das Komplizierte dabei sind aber thread-übergreifende Zugriffe auf nicht-threadsichere Objekte bzw. Methoden. Außerdem ist sicherzustellen, dass sich verschiedene Thread nicht "überholen" und damit inkonsistente Ergebnisse entstehen. Das "Überholen" kann man mit passendem Design oder ggf. synclock blockieren. Ich würde in Deiner Methode erst einmal vom ersten using bis zum Ende der foreach-Schleife den Code asynchron abarbeiten, am einfachen mit async/await, d.h. mit der Task-Klasse.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Dienstag, 18. Dezember 2018 12:51
  • Ich habe das Problem jetzt, wie folgt, gelöst:

                maskedTextBox6.Text = "busy";
                maskedTextBox6.Invalidate();
                maskedTextBox6.Update();
                maskedTextBox6.Refresh();

    Auf diese Weise wird das Textfeld schon vor Ablauf der Methode aktualisiert.

    Dienstag, 18. Dezember 2018 12:53
  • Zum zweiten Problem mit der Zeit:

    Es ist nicht schlimm, dass der parallele Thread kurzzeitig nicht arbeitet, weil die seriellen Daten gepuffert werden und dann nach Ablauf der CellDoubleClick-Methode abgerufen werden.

    Es bleibt die Frage, warum sich die Zeit zum Dateieinlesen und Anzeigen verfünffacht, nur, weil vorher eine andere Datei angezeigt wurde.

    Dienstag, 18. Dezember 2018 12:57
  • Hi Marius,
    zeig doch mal den Code mit der Stoppuhr und die Ergebnisse der Stoppuhr, mit denen nachgewiesen wird, dass es so lange dauert. Es ist möglich, dass das Betriebssystem noch mit dem Schließen beschäftigt ist und sich das erneute Öffnen geringfügig verzögert.

    Die Oberfläche mit dem Lesen der Daten zu blockieren und nur mit Tricks einzelne Anzeigen zu aktualisieren, ist keine gute Idee. Für den Anwender ist die Oberfläche in dieser Zeit eingefroren, was zu Frust und zu unüberlegtem Klicken und Abbrüchen führen kann.


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Dienstag, 18. Dezember 2018 13:59
  • Hi,

    also wäre eine Möglichkeit, um es sauberer zu programmieren, das Lesen in einen eigenen Thread auszulagern?

    Ich habe noch etwas getüftelt und festgestellt, dass die Zeit hauptsächlich auf die folgenden Zeilen zurückzuführen ist:

    chart1.Series["Temperature 1"].Points.DataBindXY(stampArray, temp1.ToArray());
    chart1.Series["Temperature 2"].Points.DataBindXY(stampArray, temp2.ToArray());

    temp1 und temp2 sind Listen:

    List<double> temp1 = new List<double>();// List of temperature values from sensor1 shown on the chart
    List<double> temp2 = new List<double>();// List of temperature values from sensor2 shown on the chart

    Wenn ich sie auskommentiere, sehe ich zwar keinen Graphen, aber beide Dateien brauchen eine gleiche, kurze Zeit von ca. 1 Sekunde.

    Es ist also anscheinend sehr anspruchsvoll, die Graphen zu überschreiben. Vielleicht lässt sich das optimieren?

    Zeilen zum Diagramm:

    chart1.Series["Temperature 1"].XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.DateTime;      // Choose DateTime as x-axis format of temp1 graph
    chart1.Series["Temperature 2"].XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.DateTime;      // Choose DateTime as x-axis format of temp2 graph
    chart1.Series["Average 1"].XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.DateTime;      // Choose DateTime as x-axis format of mt1 graph
    chart1.Series["Average 2"].XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.DateTime;      // Choose DateTime as x-axis format of mt2 graph
    chart1.ChartAreas["ChartArea1"].AxisX.LabelStyle.Format = "<dd.MM.yyyy HH:mm:ss>";                                  // Show x-axis label DateTime like: "dd.MM.yyyy HH:mm:ss"

    Die Average-Graphen sind optional durch eine Checkbox einfügbar. So kann wahlweise über eine eingegebene Zeit gemittelt werden. Die neuen Mittelwertkurven, die grobe Verläufe ohne kurze Ausschläge zeigen, werden dann zusätzlich angezeigt.

    Zu den Threads:
    Ich habe bereits einen Thread, der sich um die serielle Kommunikation kümmert, also Filenamen, Zeilen von Files, die Uhrzeit usw. liest und in Listen schreibt. Damit sich nichts in die Quere kommt, habe ich "Blockier-Variablen" eingeführt, die z.B. eine Änderung der Filenamen-Liste nicht zulassen, während bei der Synchronisation auf diese zugegriffen wird.
    Methoden rufe ich aus dem Thread ganz normal auf. Allerdings arbeiten die Methoden dann mit Invoke:

    public void addSDrow(String name)
            {
                if (InvokeRequired)
                {
                    this.Invoke(new Action<string>(addSDrow), new object[] { name });
                    return;
                }
                if (_continue)
                {
                    DataRow row = dt1.NewRow();
                    row["SD files"] = name;
                    dt1.Rows.Add(row);
                }
            }




    • Bearbeitet Marius01010 Mittwoch, 19. Dezember 2018 09:25
    Mittwoch, 19. Dezember 2018 08:44
  • Hi Marius,
    um wie viele Punkte in einer Serie handelt es sich? Ist es möglich, ohne wesentlichen Informationsverlust die Menge zu verringern (z.B. immer nur aus 5 Punkten einen Mittelwert darstellen)?

    Um welches Chart-Control handelt es sich? Gibt es für das Chart-Control Begin- und End-Edit Methoden o.ä., damit erst mit dem Zeichnen begonnen wird, wenn alle Daten zugewiesen wurden?


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Mittwoch, 19. Dezember 2018 09:17
  • Hi,

    Die Zeit wird definitiv von dem Zurücksetzen der Graphen beansprucht. Ich habe folgendes mit Breakpoints durchgetestet:

                chart1.Series["Temperature 1"].Points.Clear();
                chart1.Series["Temperature 2"].Points.Clear();
                chart1.Series["Temperature 1"].Points.DataBindXY(stampArray, temp1.ToArray());
                chart1.Series["Temperature 2"].Points.DataBindXY(stampArray, temp2.ToArray());

    Die ersten beiden Befehle brauchen die Zeit.

    Zu den Daten:

    Eine Datei hat 99632 Zeilen (Datenpunkte).
    Die Breite des Diagramms beträgt etwa 1139 Pixel. Sie passt sich allerdings der Fenstergröße an.
    Vielen Dank für die Idee.
    Das sollte den Aufwand um den Faktor 100 reduzieren. :D

    Mittwoch, 19. Dezember 2018 09:49
  • SOLVED!

    Das Lesen und Anzeigen von Dateien dauert nun immer nur etwa eine Sekunde.

    Ich habe mich einfach mal auf 2000 Datenpunkte beschränkt. So sollte jeder Full-HD-Monitor gut bedient sein.

    Vielen Dank für die Hilfe und die Ideen.

    Falls der neue Code interessiert:

    private void CellDoubleClick2(object sender, DataGridViewCellEventArgs e)                                               // Local filenames: CellDoubleClick event: Plot file
            {
                maskedTextBox6.Text = "busy";
                maskedTextBox6.Invalidate();
                maskedTextBox6.Update();
                maskedTextBox6.Refresh();
                livestream = false;                                                                                                 // Disable livestream (static graph)
                timeStamp.Clear();                                                                                                  // Clear timeStamp list
                timeStamp.TrimExcess();                                                                                             // Reset reserved memory
                temp1.Clear();                                                                                                      // Clear temp1 list
                temp1.TrimExcess();                                                                                                 // Reset reserved memory
                temp2.Clear();                                                                                                      // Clear temp2 list
                temp2.TrimExcess();                                                                                                 // Reset reserved memory
               String filename = dt2.Rows[e.RowIndex][0].ToString();                                                                // Get doubleclicked filename
                filename = filename.Replace("\r", "");                                                                              // Cut off additional return if it's there
                string path = "..\\..\\..\\..\\SDfiles";                                                                            // Set local files path
                using (var sr = new StreamReader(Path.Combine(path, filename)))                                                     // Combine path and filename, create StremReader
                {
                    string line;
                    // Current read line
                    while ((line = sr.ReadLine()) != null)                                                                          // Read until line is empty
                    {
                        string[] part = line.Split(' ');                                                                            // Split line by space
                        if (line.Length > 0)                                                                                        // If line has content
                        {
    
                            timeStamp.Add(Convert.ToDouble(part[0], new CultureInfo("en-US")));                                     // Convert unix timestamp to double and add it to timeStamp list
                            temp1.Add(Convert.ToDouble(part[1], new CultureInfo("en-US")));                                         // Convert temperature value of sensor1 to double and add it to temp1 list
                            temp2.Add(Convert.ToDouble(part[2], new CultureInfo("en-US")));                                         // Convert temperature value of sensor2 to double and add it to temp2 list
                        }
                    }
                }
                
                DateTime[] stampArray = new DateTime[timeStamp.Count];                                                              // Create stampArray with the same size as timeStap list
                int idx = 0;                                                                                                        // Initialize array index, set it to 0
                double max = Double.MinValue;   // max. time value in dataset                                                       // Initialize upper time limit and set it to the minimum (force overwrite)
                double min = Double.MaxValue;   // min. time value in dataset                                                       // Initialize lower time limit and set it to maximum (force overwrite)
                foreach (double stamp in timeStamp)                                                                                 // Repeat for every timeStamp value
                {
                    System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);                     // Create unix times reference DateTime
                    dtDateTime = dtDateTime.AddSeconds(stamp).ToUniversalTime();                                                    // Add unix timestamp
                    stampArray[idx] = dtDateTime;                                                                                   // Put calculated DateTime into array
                    idx++;
                    min = Math.Min(min, stamp);
                    max = Math.Max(max, stamp);
                }
                System.DateTime minTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
                minTime = minTime.AddSeconds(min).ToUniversalTime();
                System.DateTime maxTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
                maxTime = maxTime.AddSeconds(max).ToUniversalTime();
                maskedTextBox3.Text = minTime.ToString("dd.MM.yyyy");
                maskedTextBox5.Text = minTime.ToString("HH:mm:ss");
                maskedTextBox4.Text = maxTime.ToString("dd.MM.yyyy");
                maskedTextBox8.Text = maxTime.ToString("HH:mm:ss");
    
                setScale();
    
                time.Clear();
                time.TrimExcess();
                graph1.Clear();
                graph1.TrimExcess();
                graph2.Clear();
                graph2.TrimExcess();
    
                int averageNumber = (int)Math.Round((double)(timeStamp.Count() / 2000), MidpointRounding.ToEven);
    
                Double[] tsArray = timeStamp.ToArray();
                Double[] t1Array = temp1.ToArray();
                Double[] t2Array = temp2.ToArray();
                double sSum = tsArray[0];
                double t1Sum = t1Array[0];
                double t2Sum = t2Array[0];
    
                for (int i = 1; i < tsArray.Length; i++)
                {
                    if ((i % (averageNumber)) == 0)
                    {
                        time.Add((sSum / averageNumber));
                        graph1.Add((t1Sum / averageNumber));
                        graph2.Add((t2Sum / averageNumber));
                        sSum = 0;
                        t1Sum = 0;
                        t2Sum = 0;
                    }
                    sSum += tsArray[i];
                    t1Sum += t1Array[i];
                    t2Sum += t2Array[i];
                }
                DateTime[] timeArray = new DateTime[time.Count];
                int index = 0;
                foreach (double stamp in time)
                {
                    System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
                    dtDateTime = dtDateTime.AddSeconds(stamp).ToUniversalTime();
                    timeArray[index] = dtDateTime;
                    index++;
                }
                chart1.Series["Temperature 1"].Points.DataBindXY(timeArray, graph1.ToArray());
                chart1.Series["Temperature 2"].Points.DataBindXY(timeArray, graph2.ToArray());
                graphLoaded = true;
                maskedTextBox6.Text = "ready";
            }

    Mittwoch, 19. Dezember 2018 10:37