我知道下面的代碼是C++ - CLI,但它指的是C#以同樣的方式避免競爭條件
當我想以「結合」多行的DataGridView
,我第一次嘗試create a custom DataGridViewRow
,但這有一個缺點,即幾乎不可能實現其他類型的細胞,而不是DataGridViewTextBoxCell
。
我的下一個解決方案是創建一個自定義的DataGridView
,現在工作得很好。
它覆蓋的功能
OnCellFormatting()
OnCellPainting()
OnRowsRemoved()
OnSelectionChanged()
的問題是,經常在調試過程中,有時在正常的程序執行,我得到一個異常從內部.NET代碼,這就是所謂繪製的DataGridView或部分不同的地方的。示例:
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)
這是由於從非UI線程內一次刪除多行而引起的。實際上,一次刪除它們會很好,可以解決我的問題,但這是不可能的,因爲在刪除每一行後會調用事件。 :-(
當一行在被繪製時被刪除,這當然不能工作,這種情況會引發異常。這種情況有時候會發生,但並不總是如此,所以它肯定是刪除和paiting之間的競爭條件。 :我怎樣才能避免競爭狀態,因爲我沒有訪問,導致它的代碼
我迄今所做的:開始多行刪除之前,我設置
m_bUpdateControl = true
在所有4個被覆蓋的功能,我有
if (m_bUpdateControl)
return;
但這還沒有解決。
我已經做了旁邊:
在
OnCellFormatting()
我用if (m_bUpdateControl) { i_oEventArgs->FormattingApplied = true; return; }
在
OnCellPainting()
我用if (m_bUpdateControl) { i_oEventArgs->Handled = true; return; }
但是這還不足以安全地避免比賽情況。
我還能做什麼?
這是否會發生在常規的DGV上?
我唯一剩下的想法是在UI線程上調用行刪除的函數,所以在DGV上只會有一個線程運行,競態條件有望消失。
編輯:
我曾與一個普通DGV測試,並從非UI線程刪除行的時候總是有一個InvalidOperationException
。當然這是有道理的,因爲UI對象上的跨線程操作是不可能的。所以我想知道爲什麼在我的應用程序中可能。
我創建了一個小測試項目,最後找到原因:主應用程序實現了一個DLL。作爲賣方告訴我一個電話,主類此DLL中的初始化程序調用
Control.CheckForIllegalCrossThreadCalls = false;
這使得後續的跨線程操作。所以如果這個檢查沒有被禁用,那麼我將不得不在UI線程上進行行刪除,這很可能避免了最初的問題。