2010-01-05 1 views
6

Je suis confronté à un bug complexe avec l'outil Dundas Charting for Winforms utilisé avec MS Visual Studio 2008 C#.Red X GUI accident! J'ai presque abandonné le résoudre!

L'erreur suivante se produit lorsqu'un événement graphique est déclenché sur l'objet Graphique alors qu'il est invalide. Lorsque l'erreur se produit, le graphique dundas montre une grande marque X. ...

************** 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) 

Le scénario est le suivant:

  • J'ai une vue de la grille qui a la liste des objets qui font référence à la série étant tracée.
  • La trame est mise à jour chaque 1 seconde en utilisant chart.Invoke (AddData)

Ceci est l'événement qui provoque l'écrasement:

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; 

      } 
     } 
    } 
} 

Le dessin se fait de la manière suivante

Un fil de fond capture

Il est l'événement est

OnDataAvailable chaque seconde

Voici le gestionnaire

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

La chose intéressante à propos de ce bug est que cela ne se produit pas sur toutes les machines. J'ai remarqué que cela se produisait sur des machines à haute spécification comme notre machine CPU 8 core DELL, et un nouveau portable quad core que nous avons ici. Cela a soulevé le suspect d'un problème de filetage; cependant, le thread semble être correct puisque l'objet graphique est accessible à partir du même thread principal.

S'il vous plaît me aider

MISE À JOUR la mission en utilisant le dispositif de réglage qui se déroule dans la fonction dataGridView1_CellEndEdit MUChart.Series [boundData.SeriesName] .ChartArea = boundData.ChartArea.ToString(); appelle chart.invalidate en interne, tandis que la fonction appelée 'AddData' qui met à jour ce graphique l'appelle explicitement. J'ai lu dans la librairie MSDN que "control.invalidate" ne force pas une peinture synchrone à moins que control.update ne soit appelé après. Je suis presque certain que le conflit se passe à l'invalidation même si tout se passe sur le même fil puisque le redessin se déroule de façon asynchrone. J'ai compris ce qui se passe de cette façon mais je ne sais pas comment l'éviter. control.update ne me sert à rien.

ChangeTheChartConfigurations(); DrawTheChanges() ---- >>>> cela fonctionne de manière asynchrone UpdateDataPoints() DrawTheChanges() ---- >>> cela fonctionne tant que la première modification n'est pas encore effectuée. Par exemple, la série peut avoir été déplacée vers une zone de graphique de différence et Dundas.Charting.WinControl.AxisScale.a (Double) (la dernière fonction de la trace de pile) est appelée sur une zone de graphique déjà masquée. qui est juste une pensée

MISE À JOUR

Je me suis connecté l'ID de fil à la fois le gestionnaire d'événements et la fonction AddNewPoint et ce fut le même que le principal fil

+0

Veuillez nettoyer le formatage du code. C'est TRES difficile à lire dans son état actuel. –

+0

Je l'ai édité, c'est le meilleur qu'il pourrait obtenir – mustafabar

+0

Non ce n'est pas. Supprimez les lignes vides et indentation. – Domenic

Répondre

2

Plutôt que invalidant le tableau après avoir dessiné chaque point, tirer tous les points, puis invalider une fois le tableau. Essayez de déplacer MUChart.Invalidate() de AddNewPoint() à après la boucle for dans AddData().

1

Vous avez probablement une opération de fil croix .

Essayez de placer votre MUChart.Invalidate après que tous les points ont été ajoutés et dans le thread graphique principal.

La croix rouge est normalement dessinée par le framework .NET lui-même lorsque vous accédez à un contrôle d'interface utilisateur à partir d'un autre thread que le thread UI.

La croix est également affichée lorsqu'une ressource n'est pas disponible ou qu'une exception se produit dans le contrôle.

2

Je pense que vous ne devriez pas appeler

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

directement. Vous devez l'inclure dans le code InvokeRequired/Invoke. Et la même chose pour

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

Je suppose que vous avez un objet qui a été éliminé. (C'est le genre d'exception étrange que vous obtenez.) Une indication est votre déclaration que cela arrive sur les machines haut de gamme. Sens, la machine a effectué la collecte des ordures.

1) Que se passe-t-il lorsque vous appelez Refresh au lieu d'Invalidate?

2) Supprimer la longue chaîne de références d'objet et créer des variables. Vous comprenez que chaque {} crée une portée locale (pile). Ce qui peut entraîner une modification de la portée d'un objet pendant la mise à jour du graphique. Ne Series s = MUChart.Series[boundData.SeriesName]; ChartArea a = s.ChartArea; et ainsi de suite.

3) Essayez un objet de verrouillage ou de synchronisation dans AddNewPoint ou AddData. Aussi possible ce que vous faites n'est pas thread-safe pour le contrôle. Vérifiez la documentation.

4) Je ne placerais pas try: catch dans AddNewPoint. Mieux vaut le placer en dehors de la boucle for, mais dans votre cas, mettez-le dans la boucle.

5) Vous ne devriez pas utiliser les appels pour Actualiser, Mettre à jour et Invalider. C'est une indication que votre implémentation doit être moins lourde. (Par exemple, en supprimant l'essai: catch, abordant des événements multiples « données disponibles », à l'aide d'un verrou de synchronisation, retirez la méthode AddNewPoint.)

0

S'il vous plaît se concentrer sur l'erreur suivante:

The Interval can not be zero Parameter name: diff

Je pense que la deux valeurs pour l'axe x du graphique ont la même valeur, d'où l'exception est augmentée.

0

J'ai rencontré la même erreur et j'ai trouvé la raison pour laquelle j'ai défini AxisIntervalMode comme VaiableCount même s'il n'y a pas de données. Donc, je change dynamiquement le AxisIntervalMode selon que la série a des données. J'espère que cela peut aider quelqu'un.