2017-06-27 1 views
0

Ich weiß, dass der Code unter C++ ist - CLI, aber es bezieht sich auf C# in der gleichen Art und WeiseVermeiden Race-Bedingung in Zeile Löschen in benutzerdefinierter Datagridview

Wenn ich wollte in einem DataGridView mehr Zeilen zu „kombinieren“, Ich versuchte zuerst create a custom DataGridViewRow, aber das hatte den Nachteil, dass es fast unmöglich war, andere Zelltypen als DataGridViewTextBoxCell zu implementieren.

Meine nächste Lösung war die Erstellung einer benutzerdefinierten DataGridView, die jetzt wirklich gut funktioniert.
Sie überschreibt die Funktionen

OnCellFormatting() 
OnCellPainting() 
OnRowsRemoved() 
OnSelectionChanged() 

Das Problem ist, die oft während des Debuggens und manchmal während der normalen Programmausführung, ich eine Ausnahme aus verschiedenen Orten der internen .net Code zu erhalten, die das Datagridview oder Teile genannt wird, zeichnen davon. Beispiel:

Stack Trace: 
bei System.Windows.Forms.DataGridViewTextBoxCell.PaintPrivate(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, Int32 rowIndex, DataGridViewElementStates cellState, Object formattedValue, String errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts, Boolean computeContentBounds, Boolean computeErrorIconBounds, Boolean paint) 
bei System.Windows.Forms.DataGridViewTextBoxCell.Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, Int32 rowIndex, DataGridViewElementStates cellState, Object value, Object formattedValue, String errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) 
bei System.Windows.Forms.DataGridViewCell.PaintWork(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, Int32 rowIndex, DataGridViewElementStates cellState, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) 
bei System.Windows.Forms.DataGridViewRow.PaintCells(Graphics graphics, Rectangle clipBounds, Rectangle rowBounds, Int32 rowIndex, DataGridViewElementStates rowState, Boolean isFirstDisplayedRow, Boolean isLastVisibleRow, DataGridViewPaintParts paintParts) 
bei System.Windows.Forms.DataGridViewRow.Paint(Graphics graphics, Rectangle clipBounds, Rectangle rowBounds, Int32 rowIndex, DataGridViewElementStates rowState, Boolean isFirstDisplayedRow, Boolean isLastVisibleRow) 
bei System.Windows.Forms.DataGridView.PaintRows(Graphics g, Rectangle boundingRect, Rectangle clipRect, Boolean singleHorizontalBorderAdded) 
bei System.Windows.Forms.DataGridView.PaintGrid(Graphics g, Rectangle gridBounds, Rectangle clipRect, Boolean singleVerticalBorderAdded, Boolean singleHorizontalBorderAdded) 
bei System.Windows.Forms.DataGridView.OnPaint(PaintEventArgs e) 
bei System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer) 
bei System.Windows.Forms.Control.WmPaint(Message& m) 
bei System.Windows.Forms.Control.WndProc(Message& m) 
bei System.Windows.Forms.DataGridView.WndProc(Message& m) 
bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 
bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 
bei System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 

Dies wird dadurch verursacht, dass mehrere Zeilen gleichzeitig aus einem Nicht-UI-Thread gelöscht werden. Eigentlich wäre es einfach, sie auf einmal zu löschen und würde mein Problem lösen, aber das ist unmöglich, weil Ereignisse nach dem Löschen jeder einzelnen Zeile aufgerufen werden. :-(
Die Ausnahme wird ausgelöst, wenn eine Zeile gelöscht wird, während er gemalt wird ist, was natürlich nicht funktionieren kann. Dies ist nur manchmal und nicht immer der Fall ist, so dass es zwischen Löschen und paiting definitiv eine Race-Bedingung ist.

Meine Frage : Wie kann ich das Rennen Zustand vermeiden, da ich, dass es verursacht keinen Zugriff auf den Code haben

Was ich bisher getan haben: vor dem Löschen mehrerer Zeilen beginnen, habe ich

m_bUpdateControl = true 

In Alle 4 übersteuerten Funktionen habe ich

aber das hat es noch nicht gelöst.

Was ich als nächstes getan haben:

  • in OnCellFormatting() Ich benutze

    if (m_bUpdateControl) { i_oEventArgs->FormattingApplied = true; return; }

  • in OnCellPainting() Ich benutze

    if (m_bUpdateControl) { i_oEventArgs->Handled = true; return; }

Aber das ist immer noch nicht genug, sicher vermeiden Sie die Race-Condition.
Was könnte ich noch tun?
Wird dies auch auf einem normalen DGV passieren?

Die einzige verbleibende Idee, die ich habe, ist das Aufrufen einer Funktion zum Löschen von Zeilen im UI-Thread, sodass nur ein Thread auf dem DGV läuft und die Race-Bedingung hoffentlich verschwunden ist.

Edit:
ich mit einem regelmäßigen DGV getestet und bekam immer ein InvalidOperationException wenn Zeilen aus einem nicht-UI-Thread zu löschen. Dies ist natürlich sinnvoll, da Cross-Thread-Operationen auf UI-Objekten nicht möglich sind. Also fragte ich mich, warum es in meiner Bewerbung möglich war.
Ich erstellte ein kleines Testprojekt und fand schließlich den Grund: Die Hauptanwendung implementiert eine DLL. Da die Verkäufer mir in einem Telefonat gesagt, ruft die Init-Routine der Hauptklasse dieses DLL

Control.CheckForIllegalCrossThreadCalls = false; 

die Operationen nachfolgende verkanten ermöglicht. Wenn diese Überprüfung also nicht deaktiviert worden wäre, wäre ich gezwungen gewesen, die Zeilenlöschung auf dem UI-Thread trotzdem durchzuführen, wodurch das Anfangsproblem wahrscheinlich vermieden wird.

Antwort

0

Die Kombination von

  • die Zeilen Löschens
  • OnCellPainting() mit
    if (m_bUpdateControl) { i_oEventArgs->Handled = true; return; }

auf dem UI-Thread aufrufen scheint zu funktionieren.

Bei

void OnCellFormatting (...) 
{ 
    DataGridView::OnCellFormatting (i_oEventArgs); 

    if (IsConsecutiveCell (i_oEventArgs->RowIndex, i_oEventArgs->ColumnIndex)) 
    { 
    i_oEventArgs->Value = String::Empty; 
    i_oEventArgs->FormattingApplied = true; 
    } 
} 

Ich hatte alle Schutz zu entfernen, so dass der DGV nicht mit Zellen, die mit verschiedenen Arten von Inhalten in der gleichen Spalte am Ende, die ein andere Fehlermeldung und Ausnahme verursacht hat.

Ich möchte noch andere Lösungen kennen, wenn vorhanden.

Verwandte Themen