2011-02-08 40 views
1

我有一個DataGridView在C#(.NET 2.0)與幾個只讀單元(3 25)。我正在使用頂級回答here中概述的方法在Form_Load處理程序中的這些特定單元上設置ReadOnly。該鏈接的問題指出,如何通過DataGridView上的單元格導航(選項卡/箭頭)跳過只讀單元格?

有些細胞具有當用戶與TAB導航或細胞間ENTER是隻讀的,而且,只讀細胞應該繞過

所以我認爲設置標誌將導致要跳過的單元格。

長話短說,不是。即使無法編輯,只讀單元格也會被選中並選中。我正在梳理DataGridView的屬性,尋找某種TabMode或TabSkipsReadOnlyCells屬性,但目前爲止還沒有。是否有爲此行爲設置的屬性,還是必須編寫某種標籤事件處理代碼?

這似乎是它應該是默認的行爲,所以我有點惱火,甚至必須找到它的屬性,更需要編寫代碼來做到這一點...

編輯:我應該澄清一下,我對使用Tab鍵處理導航不感興趣。我想用箭頭鍵和鼠標來實現合理的導航。這意味着,如果我有寫代碼,我需要在其中選擇移動時我蹦蹦跳跳出來一個只讀細胞的直接控制,可能通過在DataGridView設置CurrentCell。這樣,如果用戶向上箭頭進入只讀單元格,我可以重定向到上面的單元格,而不是總是到右側的單元格。

編輯2:這是我的最終解決方案,操控箭頭鍵導航以及標籤導航,基於Sean Griffiths' code(也是公認的答案鏈接):

private void GridForm_Load(object sender, EventArgs e) 
{ 
    dataGridView1.CellEnter += dataGridView1_CellEnter; 
} 

//a delegate is needed to avoid a circular loop when selecting a cell when in a cell selection event 
private delegate void SetColumnAndRowOnGrid(DataGridView grid, int columnIndex, int rowIndex); 
static SetColumnAndRowOnGrid setCellMethod = new SetColumnAndRowOnGrid(setGridCell); 

// Method pointed to by the delegate 
private static void setGridCell(DataGridView grid, int columnIndex, int rowIndex) 
{ 
    grid.CurrentCell = grid.Rows[rowIndex].Cells[columnIndex]; 
    grid.BeginEdit(true); 
} 

// Track the cell we leave so we can determine direction of "travel" 
int _lastRow = 0, _lastCol = 0; 
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e) 
{ 
    _lastRow = e.RowIndex; 
    _lastCol = e.ColumnIndex; 
} 

enum Direction { Up, Down, Left, Right } 

// When we enter a read only cell, determine direction 
// of "travel" and keep going that way 
private void dataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e) 
{ 
    int currRow = e.RowIndex; 
    int currCol = e.ColumnIndex; 
    if (dataGridView1.Rows[currRow].Cells[currCol].ReadOnly) 
    { 
     Direction direction = Direction.Right; 
     if ((currRow != _lastRow) && (currCol == _lastCol)) 
     { 
      // moving vertically 
      if (currRow < _lastRow) direction = Direction.Up; 
      else direction = Direction.Down; 
     } 
     else 
     { 
      // moving horizontally 
      if (currCol == 0 && 
       _lastCol == dataGridView1.Columns.Count - 1 && 
       currRow == _lastRow + 1) 
      { 
       // Special case - probably just tabbed from end of row 
       direction = Direction.Right; 
      } 
      else if (currCol == dataGridView1.Columns.Count - 1 && 
       _lastCol == 0 && 
       currRow == _lastRow - 1) 
      { 
       // Special case - probably just shift-tabbed from start of row 
       direction = Direction.Left; 
      } 
      else if (currCol < _lastCol) { direction = Direction.Left; } 
     } 
     //this cell is readonly, find the next tabable cell 
     if (!SetNextTabableCell(dataGridView1, currCol, currRow, direction)) 
     { 
      // All the cells in the grid have been tried, none could be tabbed 
      // to so move onto the next control 
      bool tabForward = direction == Direction.Right || direction == Direction.Down; 
      SelectNextControl(this, tabForward, true, true, true); 
     } 
    } 
} 

// Find the next cell that we want to be selectable 
private static bool SetNextTabableCell(DataGridView grid, int nextColumn, int nextRow, Direction direction) 
{ 
    //keep selecting each next cell until one is found that isn't either readonly or invisible 
    int maxMoves = grid.ColumnCount * grid.RowCount; 
    int moves = 0; 
    do 
    { 
     if (!GetNextCell(grid, ref nextColumn, ref nextRow, ref direction)) return false; 
     // Prevent infinite loop - I managed to get in one when this function 
     // wound up in a readonly column with a direction of Down (if we've moved 
     // to another cell more times than there are cells in the grid, just give up) 
     if (++moves > maxMoves) return false; 
    } 
    while (grid.Rows[nextRow].Cells[nextColumn].ReadOnly == true || 
       grid.Rows[nextRow].Cells[nextColumn].Visible == false); 

    //a cell has been found that can be entered, use the delegate to select it 
    grid.BeginInvoke(setCellMethod, grid, nextColumn, nextRow); 
    return true; 
} 

// Get the next cell in the indicated direction 
// Wrap around if going left-right 
// Bounce at the edge if going up/down 
private static bool GetNextCell(DataGridView grid, ref int nextColumn, ref int nextRow, ref Direction direction) 
{ 
    switch (direction) 
    { 
     case Direction.Right: 
      if (nextColumn < grid.Columns.Count - 1) 
      { 
       // Nominal case - move right one cell 
       nextColumn = nextColumn + 1; 
      } 
      else // at the last column 
      { 
       // go the the first column 
       nextColumn = 0; 
       if (nextRow < grid.Rows.Count - 1) 
       { 
        // Nominal case - move down one row 
        nextRow = nextRow + 1; 
       } 
       // at the last row and last column exit this method, no cell can be selected 
       else { return false; } 
      } 
      break; 
     case Direction.Left: 
      if (nextColumn > 0) 
      { 
       // Nominal case - move left one cell 
       nextColumn = nextColumn - 1; 
      } 
      else // at the first column 
      { 
       // go the the last column 
       nextColumn = grid.Columns.Count - 1; 
       if (nextRow > 0) 
       { 
        // Nominal case - move up one row 
        nextRow = nextRow - 1; 
       } 
       // at the first row and first column exit this method, no cell can be selected 
       else { return false; } 
      } 
      break; 
     case Direction.Down: 
      if (nextRow < grid.Rows.Count - 1) 
      { 
       // Nominal case - move down one cell 
       nextRow = nextRow + 1; 
      } 
      else // at the last row 
      { 
       // turn around 
       nextRow = nextRow - 1; 
       direction = Direction.Up; 
      } 
      break; 
     case Direction.Up: 
      if (nextRow > 0) 
      { 
       // Nominal case - move up one cell 
       nextRow = nextRow - 1; 
      } 
      else // at the first row 
      { 
       // turn around 
       nextRow = nextRow + 1; 
       direction = Direction.Down; 
      } 
      break; 
     default: return false; 
    } 
    return true; 
} 

如果有人利用這一點,並認爲情況下,它行爲不好,我想聽聽,所以我希望可以通過修復來更新。

編輯3:增加了一個安全櫃檯後的代碼託管今天拿到自己在一個無限循環的狀態。在零列所有細胞設置爲只讀,並且第一次點擊進入電網控制在零列,所以它試圖向下移動,然後向上,再往下....

+0

哦,當然,右後,我張貼相關列表彈出一個可能的重複:http://stackoverflow.com/questions/751981/bypass-read-only-cells-in- datagridview的,當壓片定位鍵 – 2011-02-08 18:48:14

+0

設置`調焦= FALSE;`當你設置的小區爲只讀?或'接受tab = FALSE;` – FlyingStreudel 2011-02-08 18:48:22

+0

智能感知沒有顯示我的DataGridViewCell的還是它的樣式屬性調焦或tab屬性。這是一個.NET 3或更好的屬性? – 2011-02-08 18:51:34

回答

3

你將不得不投入做這件事的是 一種方式的一些代碼是

void grd_CellEnter(object sender, DataGridViewCellEventArgs e) 
{    
    if(grd[e.ColumnIndex,e.RowIndex].ReadOnly) 
     SendKeys.Send("{TAB}"); 
} 
相關問題