2017-06-27 297 views
0

我知道下面的代碼是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線程上進行行刪除,這很可能避免了最初的問題。

回答

0

  • 調用行刪除UI線程
  • OnCellPainting()
    if (m_bUpdateControl) { i_oEventArgs->Handled = true; return; }

的組合似乎工作。

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

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

,我不得不刪除所有的保護,使得DGV沒有與不同類型的在同一列中,這引起了另一個錯誤信息和異常內容的單元格結束。

我仍然想知道其他解決方案,如果存在。