6 Stimmen

Red X GUI stürzt ab! Ich habe fast aufgegeben, das Problem zu lösen!

Ich stehe vor einem komplexen Fehler mit dem Dundas Charting for Winforms-Tool, das mit MS Visual Studio 2008 C# verwendet wird.

Der folgende Fehler tritt auf, wenn ein GUI-Ereignis für das Chart-Objekt ausgelöst wird, während es ungültig gemacht wird. Wenn der Fehler auftritt, zeigt das Dundas-Diagramm ein großes X an. ...

************** Exception Text **************

System.ArgumentOutOfRangeException: Axis Object - The Interval can not be zero
Parameter name: diff
   at Dundas.Charting.WinControl.AxisScale.a(Double )
   at Dundas.Charting.WinControl.Axis.a(Double , Double , AxisScaleSegment , DateTimeIntervalType& )
   at Dundas.Charting.WinControl.Axis.a(ChartGraphics , Boolean , AxisScaleSegment , Boolean )
   at Dundas.Charting.WinControl.Axis.b(ChartGraphics , Boolean , Boolean )
   at Dundas.Charting.WinControl.Axis.Resize(ChartGraphics chartGraph, ElementPosition chartAreaPosition, RectangleF plotArea, Single axesNumber, Boolean autoPlotPosition)
   at Dundas.Charting.WinControl.ChartArea.a(ChartGraphics )
   at Dundas.Charting.WinControl.ChartPicture.Resize(ChartGraphics chartGraph, Boolean calcAreaPositionOnly)
   at Dundas.Charting.WinControl.ChartPicture.Paint(Graphics graph, Boolean paintTopLevelElementOnly, RenderingType renderingType, XmlTextWriter svgTextWriter, Stream flashStream, String documentTitle, Boolean resizable, Boolean preserveAspectRatio)
   at Dundas.Charting.WinControl.ChartPicture.Paint(Graphics graph, Boolean paintTopLevelElementOnly)
   at Dundas.Charting.WinControl.Chart.OnPaint(PaintEventArgs e)
   at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
   at System.Windows.Forms.Control.WmPaint(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Das Szenario sieht folgendermaßen aus:

  • Ich habe eine Gitteransicht, die eine Liste von Objekten enthält, die auf die darzustellende Serie verweisen.
  • Die Darstellung wird alle 1 Sekunde mit chart.Invoke(AddData) aktualisiert.

Dies ist das Ereignis, das den Absturz verursacht:

private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
    {
        AppDataSeries boundData =
dataGridView1[e.ColumnIndex, e.RowIndex].OwningRow.DataBoundItem as AppDataSeries;

        if (boundData.Tag != null)
        // Tag is of Type Dundas.Charting.WinControl.Series
        {
            switch (e.ColumnIndex)
            {
                case 1:
                    MUChart.Series[boundData.SeriesName].ChartArea = 
                          boundData.ChartArea.ToString();
                    // when you change the chart area of a series it
                    // crashes the chart control
                    // also when you enable or disable a series using
                    // series1.Enabled = true,
                    // it could crash the chart control
                    MUChart.ChartAreas[boundData.ChartArea].Visible = true;
                    break;

            }
        }
    }
}

Die Zeichnung wird auf folgende Weise angefertigt

Ein Hintergrund-Thread erfasst

Sie hebt das Ereignis

OnDataAvailable jede Sekunde

Hier ist der Handler

void serviceWrapperInstance_DataAvailable(object sender, DataAvailableEventArgs e)
{
    if (e.ViewId == currentViewId)
    {
        if (MUChart.InvokeRequired)
        {
            MUChart.Invoke((MethodInvoker)AddData);
        }

        else
        {
            AddData();
        }
    }
}
public void AddData()
{
    if (MUChart.Series.Count > 0)
    {
        for (int i = 0; i < currentViewSeries.Count; i++)
        {
            AddNewPoint(currentViewSeries[i].XValue, MUChart.Series[i],
currentViewSeries[i].YValue * ((currentViewSeries[i].IsInverse) ? -1 : 1),
currentViewSeries[i].ChartColor);

            dataSaver[MUChart.Series[i].Name].Add(new DataPoint(currentViewSeries[i].XValue,
(double)currentViewSeries[i].YValue));

        }
    }
}
public void AddNewPoint(double xValue, Series ptSeries, double yValue,
Color pointColor)
{
    try
    {
        ptSeries.Points.AddXY(xValue, yValue);
        if (draggedDroppedSeriesMapper.ContainsKey(ptSeries))
            foreach (Series item in draggedDroppedSeriesMapper[ptSeries].DraggedDroppedSeriesVersions)
                item.Points.AddXY(xValue, yValue);
        MUChart.Invalidate();
        // if I remove the previous line the plot doesn’t crash, but doesn’t update !!
    }
    catch (Exception ex)
    {
        Logger.Log(TraceLevel.Error, "AddNewPoint()", ex);
    }
}

Das Interessante an diesem Fehler ist, dass er nicht auf allen Rechnern auftritt. Mir ist aufgefallen, dass er auf Hochleistungsrechnern wie unserem DELL-Rechner mit 8-Kern-CPU und einem neuen Quad-Core-Laptop auftritt, den wir hier gekauft haben. Dies ließ den Verdacht aufkommen, dass es sich um ein Threading-Problem handelt; allerdings scheint das Threading in Ordnung zu sein, da auf das Diagrammobjekt von demselben Haupt-Thread aus zugegriffen wird.

Bitte helfen Sie mir dabei

UPDATE die Zuordnung über den Setter, der in der Funktion dataGridView1_CellEndEdit stattfindet MUChart.Series[boundData.SeriesName].ChartArea = boundData.ChartArea.ToString(); ruft chart.invalidate intern auf, während die aufgerufene Funktion "AddData", die das Diagramm aktualisiert, diese Funktion explizit aufruft. Ich habe in der MSDN-Bibliothek gelesen, dass "control.invalidate" keine synchrone Zeichnung erzwingt, wenn control.update nicht danach aufgerufen wird. Ich bin mir fast sicher, dass der Konflikt bei der Invalidierung auftritt, obwohl alles auf demselben Thread abläuft, da das Neuzeichnen asynchron erfolgt. Ich habe verstanden, was auf diese Weise geschieht, aber ich weiß nicht, wie ich es vermeiden kann. control.update tut mir nicht gut.

ChangeTheChartConfigurations(); DrawTheChanges() ---- >>>> dies funktioniert asynchron UpdateDataPoints() DrawTheChanges() ---- >>> dies funktioniert, während die erste Änderung noch nicht stattgefunden hat. Zum Beispiel könnte die Serie in einen anderen Diagrammbereich verschoben worden sein und Dundas.Charting.WinControl.AxisScale.a(Double ) (die letzte Funktion im Stacktrace) wird auf einem bereits ausgeblendeten Diagrammbereich aufgerufen das ist nur ein Gedanke

UPDATE

Ich habe die Thread-ID sowohl vom Event-Handler als auch von der AddNewPoint-Funktion protokolliert, und sie war dieselbe wie die des Hauptthreads

0 Stimmen

Bitte bereinigen Sie die Formatierung des Codes. In seinem jetzigen Zustand ist er SEHR schwer zu lesen.

0 Stimmen

Ich habe es bearbeitet, besser geht es nicht

0 Stimmen

Nein, ist es nicht. Entfernen Sie Leerzeilen und entfernen Sie die Einrückung.

2voto

Fedor Punkte 43061

Ich denke, Sie sollten nicht anrufen

MUChart.Series[boundData.SeriesName].ChartArea = boundData.ChartArea.ToString();

direkt. Sie sollten es in InvokeRequired/Invoke-Code verpacken. Und dasselbe gilt für

MUChart.ChartAreas[boundData.ChartArea].Visible = true;

2voto

fupsduck Punkte 3071

Anstatt das Diagramm nach dem Zeichnen jedes Punktes ungültig zu machen, zeichnen Sie alle Punkte und machen Sie das Diagramm dann einmal ungültig. Versuchen Sie, MUChart.Invalidate() von AddNewPoint() nach der for-Schleife in AddData() zu verschieben.

1voto

Wahrscheinlich haben Sie ein Kreuzgewinde.

Versuchen Sie, Ihre MUChart.Invalidate zu platzieren, nachdem alle Punkte hinzugefügt wurden und im Haupt-GUI-Thread.

Das rote Kreuz wird normalerweise vom .NET-Framework selbst gezeichnet, wenn Sie auf ein UI-Steuerelement von einem anderen Thread als dem UI-Thread aus zugreifen.

Das Kreuz wird auch angezeigt, wenn eine Ressource nicht verfügbar ist oder eine Ausnahme in dem Control auftritt, die angezeigt werden soll.

1voto

AMissico Punkte 21179

Ich vermute, Sie haben ein Objekt, das entsorgt wurde. (Dies ist die Art der seltsamen Ausnahme, die Sie erhalten.) Ein Hinweis ist Ihre Aussage, dass es auf High-End-Maschinen passiert. Das bedeutet, dass der Rechner eine Garbage Collection durchgeführt hat.

1) Was passiert, wenn Sie Refresh anstelle von Invalidate aufrufen?

2) Entfernen Sie die lange Kette von Objektverweisen und erstellen Sie Variablen. Sie wissen, dass jedes {} einen lokalen Bereich (Stack) erzeugt. Das kann dazu führen, dass sich der Bereich eines Objekts ändert, während das Diagramm aktualisiert wird. Machen Sie Series s = MUChart.Series[boundData.SeriesName]; ChartArea a = s.ChartArea; und so weiter.

3) Versuchen Sie eine Sperre oder ein synchronisierendes Objekt in AddNewPoint oder AddData. Es ist auch möglich, dass das, was Sie tun, für das Steuerelement nicht thread-sicher ist. Prüfen Sie die Dokumentation.

4) Ich würde das try:catch nicht in AddNewPoint platzieren. Besser ist es, es außerhalb der for-Schleife zu platzieren, aber in Ihrem Fall setzen Sie es in die Schleife.

5) Sie sollten wirklich keine Aufrufe zu Refresh, Update und Invalidate verwenden. Dies ist ein Hinweis darauf, dass Ihre Implementierung weniger CPU-Zyklus-lastig sein muss (z. B. Entfernen von try:catch, Adressierung mehrerer "Data Available"-Ereignisse, Verwendung einer Sync-Sperre, Entfernen der AddNewPoint-Methode).

0voto

Thunder Punkte 9735

Bitte konzentrieren Sie sich auf den folgenden Fehler:

Das Intervall kann nicht Null sein Parameter Name: diff

Ich denke, dass die beiden Werte für die X-Achse des Diagramms denselben Wert haben und daher die Ausnahme ausgelöst wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X