2013-06-28 44 views
0

此問題通常適用於標準DataGridView。出於某種原因,即使在用戶單擊列標題對DataGridView進行排序時,即使沒有選擇任何單元格(選擇已清除),排序後也會始終選擇一個單元格。爲了解釋我爲什麼不想要這個,我需要提供一些關於我的項目的背景。DataGridView排序會導致單元格被選中,即使在排序之前已清除選擇內容

我需要擴展DataGridView的功能,同時保持數據綁定完好無損。首先,我需要將數據組織成可展開/可摺疊的組。後來,其他功能已經專門爲DataGridView(由其他人編寫)將被添加。這意味着我沒有自由使用不是圍繞DataGridView構建的第三方網格組件。

因此,我決定使用由HotDog(Robert Verpalen)編寫的DataGridViewGrouper組件,他的代碼請參閱this link。在此組件中,摺疊的行通過將其可見屬性設置爲false而隱藏。

原則上它的工作原理是,直到我嘗試在選擇了一個組行後排序數據。在這種情況下,它會引發一個錯誤:ArgumentOutOfRangeException。我想我會走捷徑來解決這個問題,並補充說:

private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e) 
{ 
if (dataGridViewGrouper1.CurrentRowIsGroupRow) 
    { 
     dataGridView1.ClearSelection(); 
    } 
} 

沒有理由爲什麼用戶必須能夠選擇組行之一,並清除他們的選擇擺脫錯誤的當我嘗試分類時,我得到了。 但是,排序後總會有一個單元格被選中;即使在排序之前選擇已被清除。

我已經添加了一個CellMouseDown事件來跟蹤在排序之前最後選擇了哪個單元格,以便排序後我可以再次選擇同一個單元格(而不是恰好坐在同一行索引處的單元格) 。

private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e) 
{ 
if (e.RowIndex == -1) 
    { 
     if (dataGridView1.SelectedCells.Count == 0) { return; } 
     selected = dataGridView1.Rows[dataGridView1.SelectedCells[0].RowIndex].Cells[0].Value.ToString(); 
    } 
} 

如果沒有選定的單元格(這裏沒有任何要記住的),我從這個方法返回。事實上,如果在最後一次選擇組行後進行排序,確實發生了這種情況,這意味着我嘗試清除該選擇是成功的。

但是,在這種情況下排序後仍然選擇一個單元格。這是一個看似隨機選擇的小組。我懷疑它與選擇被清除之前選擇的單元的位置有某種關係。這會導致相當令人討厭的行爲,例如屏幕跳轉到選定單元格的位置(幾百行距離)或摺疊組中的不可見行在選中時變得可見。

我找不到在哪個事件中選擇了單元格。我試着跟蹤排序之前選擇哪個組行,以便稍後可以選擇其他內容,並且如果有必要使該組中的所有行都不可見,但我沒有管理。我也覺得這不是解決這個問題的正確方法。

類似地,在進入排序操作而不是清除選擇之前,使用循環來選擇最接近的可見數據單元似乎不是一個很好的解決方案。特別是因爲當所有組合都摺疊時(沒有可見的數據行),我仍然會遇到問題。

我真正想要的(我認爲)是在排序之後停止選擇一個單元格,如果在排序之前沒有選擇一個單元格。有人可以幫助我嗎?

+0

雖然這是一箇舊帖子,但我想知道您是否仍在使用該組件。博客上發佈的代碼是一箇舊的主要版本,並已有許多更新(爲了清楚起見,我的vbcity名稱是hotdog)。自舊的vbcity博客關閉以來,我得到了有人正在查找代碼的想法,並且正在考慮將新版本上傳到代碼項目。 (儘管現在的版本已經停滯了一段時間) –

+0

我們仍然使用這個組件,做了一些調整。查看更新版本的代碼肯定會很有趣。 – 5Ke

+0

組件和代碼現在可以在這裏找到:http://www.codeproject.com/Tips/995958/DataGridViewGrouper –

回答

0

您是否嘗試過設置CurrentCellSelected屬性爲False,如:

dataGridViewName.CurrentCell.Selected = false; 
+0

我現在已經(在dataGridView1_CellMouseClick事件中)...但它不起作用。我得到和以前完全一樣的行爲。感謝您試圖幫助! – 5Ke

2

每次調用排序(),DataBindingCompleted事件也上升(很討厭),這樣即使你在DataGridView中選擇被清除,BindingContext中[ dataGridView1.DataSource] .Position不會更改,並且在排序(我認爲)後,您的選擇會自動設置爲數據源中的當前位置。

爲了解決這個問題,無論是在排序前重置您的數據的位置:

void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) 
     { 
      if (e.RowIndex == -1) 
      { 
       if (dataGridView1.DataSource != null) 
       { 
        BindingContext[dataGridView1.DataSource].Position = 0; 
       } 
      } 
     } 

或排序後刪除選擇

void dataGridView1_Sorted(object sender, EventArgs e) 
     { 
      if (dataGridView1.SelectedCells.Count > 0) 
      { 
       dataGridView1.ClearSelection(); 
      } 
     } 

EDIT(提防,要麼不改變位置!) : 我發現了一些醜陋的黑客攻擊,儘管它要求覆蓋DataGridView保護的功能。此外,我沒有完全測試它,所以稍後可能會導致一些奇怪的行爲(無擔保)。但它在基本設置中起作用。首先,請撥打dataGridView1.ClearSelection(); CellClick上的,如果列標題被點擊。然後:

public class DGV:DataGridView 
{ 
     bool isSorted = false; 

     public override void Sort(DataGridViewColumn dataGridViewColumn, System.ComponentModel.ListSortDirection direction) 
     { 
      isSorted = true; 
      base.Sort(dataGridViewColumn, direction); 
     } 
     protected override void OnSorted(EventArgs e) 
     { 
      base.OnSorted(e); 
      isSorted = false; 

     } 

protected override void SetSelectedCellCore(int columnIndex, int rowIndex, bool selected) 
     { 
      // here is where cell gets selected so just ignore it when sorting 
      if (isSorted) 
      { 
       return; 
      } 

      base.SetSelectedCellCore(columnIndex, rowIndex, selected); 
} 
} 
+0

我嘗試了兩種方法,但都沒有解決這樣一個事實,即在對所有組進行排序後,在某個點處選擇了一行,並且該行變爲可見。不過,我更多地關注這個DataBindingCompleted事件!感謝您將它的存在指向我! – 5Ke

+0

再次感謝。這SetSelectedCellCore位聽起來很有希望!我將你的類複製到了我的命名空間中,但是在調試時,我永遠不會達到我設置的斷點。我打算做一些關於使用override來研究我是否把代碼放錯了的研究。我看到,覆蓋也在DataGridViewGrouper組件的ApplySort上使用。也許我試圖推翻那些已經「超越」的東西......如果你對此有任何想法,請告訴我。 – 5Ke

+0

我結束了欺騙我的出路。 datagridviewgrouper竟然有一個grid_sorted事件。我現在清除了這個事件中的選擇,然後只是回憶所有應該崩潰的組。感謝您幫助我更好地理解DataGridView組件! – 5Ke