2013-07-30 90 views
1

我有一個DataGridView複選框。複選框被自動引入,因爲我的數據源有一個布爾型「Selected」屬性(如果有的話)。覆蓋檢查事件

使用谷歌搜索forums在這裏我已經能夠實現一個互相排斥機制的工作好。

// unselect all the other ones 
foreach (DataGridViewRow dgvr in dataGridView1.Rows) 
{ 
    ((DataGridViewCheckBoxCell)dgvr.Cells[e.ColumnIndex]).Value = false; 
} 
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = true; 

問題是如果用戶單擊一個複選框,該框取消選中。這裏的用例是必須始終選擇一些東西。

我的第一種方法是確保現有列索引的值設置爲true。它是。但問題仍然存在......

我的第二種方法是將DataGridViewCellEventArgs的處理事件設置爲true,以阻止任何下游事件干擾我們的特定用例條件。顯然這個類沒有處理過的屬性(它的基類也沒有)。

我的第三種方法是調用Application.DoEvents()一萬次,然後將Value設置爲true以查看是否取消選中該框將在該處處理,然後我可以撤消它。但顯然這個過程直到事件處理程序方法完成之後纔會發生。

我該怎麼做?

+0

你的問題我也不清楚。我沒有得到你想要的datagridview,你想做一些類似你發佈的代碼,但你不想使用'foreach'或者任何'loop'? –

+0

@KingKing:嗯,我想我需要那個。問題是,有些如何似乎有一些其他過程,不檢查我在那裏檢查了什麼。 – micahhoover

回答

1

這裏的用例是必須始終選擇某個東西。

您需要處理datagridview的CellContentClick。然後你可以檢查是否有任何複選框仍然被選中。完成之後,您可以根據您的使用情況調用CancelEditCommitEdit

+0

這使我得到了一些方法(所以+1)。不幸的是,雙擊事件似乎可以解決這個問題。我嘗試創建一個虛擬的雙擊方法,並將兩個事件引導到相同的方法,但都不起作用。 – micahhoover

+0

你能分享你的更新代碼嗎? – Ehsan

1

這可能會幫助:

// A list of the check box cell so we can use LINQ to access them 
private List<DataGridViewCheckBoxCell> checkBoxCellList = new List<DataGridViewCheckBoxCell>(); 

private DataGridView dgv = new DataGridView(); 

private void dataGridViewBuild() { 
    DataGridViewCheckBoxColumn cbcolumn = new DataGridViewCheckBoxColumn(false); 
    cbcolumn.Name = "Selected"; 
    cbcolumn.HeaderText = cbcolumn.Name;    
    this.dgv.Columns.Add(cbcolumn); 

    // Add 100 rows 
    for (int i = 0; i < 100; i++) { 
     dgv.Rows.Add(); 
    } 

    // Get all of the checkbox cells and add them to the list 
    foreach (DataGridViewRow row in this.dgv.Rows) {     
     this.checkBoxCellList.Add((DataGridViewCheckBoxCell)row.Cells["Selected"]); 
    }    

    // Subscribe to the value changed event for the datagridview 
    this.dgv.CellValueChanged += new DataGridViewCellEventHandler(dgv_CellValueChanged);    

    this.Controls.Add(this.dgv); 
} 

void dgv_CellValueChanged(object sender, DataGridViewCellEventArgs e) { 

    // Get the cell checkbox cell for the row that was changed 
    DataGridViewCheckBoxCell checkBoxCell = (DataGridViewCheckBoxCell)this.dgv[e.ColumnIndex, e.RowIndex]; 

    // If the value is true then set all other checkboxcell values to false with LINQ 
    if (checkBoxCell.Value != null && Convert.ToBoolean(checkBoxCell.Value)) { 
     this.checkBoxCellList.FindAll(cb => Convert.ToBoolean(cb.Value) == true && cb != checkBoxCell).ForEach(cb => cb.Value = false); 
    } 

    // If the checkboxcell was made false and no other is true then reset the value to true  
    if (this.checkBoxCellList.FindAll(cb => Convert.ToBoolean(cb.Value) == true).Count == 0) { 
      checkBoxCell.Value = true; 
    } 
} 
+0

檢查並取消選中複選框單元格時,「CellValueChanged」甚至沒有被觸發?我已經測試過這個事件,這有點奇怪,也許只適用於checkboxcell。 –

+0

將數據保存到datagridview時觸發。點擊複選框,然後點擊另一行,它應該會觸發。 – jiverson

+0

@jiverson:我有和KingKing一樣的經歷。我沒有看到該事件被可靠地解僱。 +1將我介紹給foreach lambda方法。最後我檢查了它不在101 linq教程中。 – micahhoover

0

我的一個同事(本Zoski)建議乾脆,只是去掉複選框使用數據網格視圖的自然點擊選擇唯一標識行:

enter image description here

爲此,我將數據網格視圖的SelectionMode屬性設置爲:「FullRowSelect」。

我有點擔心用戶不會熟悉突出顯示網格中的特定行以選擇某些內容(與熟悉檢查框的方式相同),但單個複選框方法是複雜和不可靠的(儘管我懷疑如果你希望用戶能夠選擇多行,這是一個更好的方法)。

0

看起來像你通過改變方向來回答自己的問題,但我想我會拋出一個可能的解決方案,以防止你想要堅持使用CheckBoxes。考慮以下代碼:

private static int _previousClickedCheckBoxRowIndex; 

private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e) 
{ 
    var dgv = (DataGridView)sender; 

    if ((dgv.IsCurrentCellDirty) & (dgv.CurrentCell.OwningColumn == dgv.Columns["CheckBoxColumn"])) 
    { 
     dgv.CommitEdit(DataGridViewDataErrorContexts.Commit); 
    } 
} 

private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) 
{ 
    var dgv = (DataGridView)sender; 

    if (dgv.Columns[e.ColumnIndex] == dgv.Columns["CheckBoxColumn"]) 
    { 
     dgv.CellValueChanged -= dataGridView1_CellValueChanged; 

     if (_previousClickedCheckBoxRowIndex == e.RowIndex) 
     { 
      dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = 
       !((bool)dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value); 

      dgv.RefreshEdit(); 

     } 
     else 
     { 
      dgv.Rows[_previousClickedCheckBoxRowIndex].Cells["CheckBoxColumn"].Value = false; 
      _previousClickedCheckBoxRowIndex = e.RowIndex;        
     } 

     dgv.CellValueChanged += dataGridView1_CellValueChanged; 
    } 
} 

基本上什麼代碼正在做的是,通過保持最後的CheckBox行索引的用戶在你的DataGridView點擊的軌道,它會要麼拒絕來自未檢查只檢查當前用戶框,或者將該框切換爲獨立檢查,如果它以前未被選中。

處理CurrentCellDirtyStateChanged的原因是,默認情況下,DataGridView在編輯模式下離開CheckBoxCell。這將它作爲對網格的更改提交。取消訂閱然後重新訂閱CellValueChanged事件的原因是爲了防止在程序中更改函數內部的值時出現無限循環。

確保您更改索引字符串「CheckBoxColumn」到列在您的網格。

不是最優雅的代碼,但它是相當簡短而親切。如果你決定走這條路,希望它對你有用。