顯示具有 DataGridView 標籤的文章。 顯示所有文章
顯示具有 DataGridView 標籤的文章。 顯示所有文章

2015年6月10日 星期三

[除錯] DataGridView RowValidating事件, 當按Escape取消時, 不要引發該事件...

as title...

參考:
Escaping DataGridView Row creation fires RowValidating. How to avoid this?

1)
private void dataGridView1_KeyDown(object sender, KeyEventArgs e) 
{ 
     if (e.KeyCode == Keys.Escape) 
     { 
          this.dataGridView1.RowValidating -= 
               new System.Windows.Forms.DataGridViewCellCancelEventHandler(this.dataGridView1_RowValidating); 
     } 

     this.dataGridView1.RowValidating += 
          new System.Windows.Forms.DataGridViewCellCancelEventHandler(this.dataGridView1_RowValidating); 
}


2)
if (!view.IsCurrentRowDirty ) return; 


2014年5月14日 星期三

[學習] DataGridView 設置 Column 顯示的格式為百分比

目的:
將Column的格式設置為百分比!

法一:    
DataGridView1.DataSource = dt
DataGridView1.Columns("新增次數").Visible = False
DataGridView1.Columns("供應商成交率").DefaultCellStyle.Format = "p"
DataGridView1.Columns("集團成交率").DefaultCellStyle.Format = "p"

法二:

Private Sub DataGridView1_CellFormatting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) Handles DataGridView1.CellFormatting
      If Me.DataGridView1.Columns(e.ColumnIndex).Name = "供應商成交率" OrElse Me.DataGridView1.Columns(e.ColumnIndex).Name = "集團成交率" Then
          If e.Value IsNot Nothing Then
              e.Value = e.Value * 100 & "%"
          End If
      End If
End Sub

結果:
(1)原始資料


(2)顯示資料







參考:
DataGridView中显示百分比
DataGridView.CellFormatting 事件
格式化 Windows Form DataGridView 控制項中的資料
[C#] 字串輸出格式
string.Format 格式參數
23654.3654          Result
N0 取整數           23654
N1 取一位數       23654.3
N2 取二位數       23654.36(若有進位就 23654.37)
以此類推
DataGridView 控制項 (Windows Form)

[ASP.NET] Gridview 欄位輸出格式 DataFormatString
http://msdn.microsoft.com/zh-tw/library/vstudio/f9x2790s(v=vs.100).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1

2013年11月14日 星期四

[除錯] 因為程式無法認可或結束儲存格值的變更

情況:
承自 DataGridView 的擴展控項 myDataGridView
當CellValidating...沒過...Coding為e.cancel=true;
則程式最先進入控項的ProcessDialogKey...
當Cdoing為base.CurrentCell = base.Rows[base.CurrentCell.RowIndex].Cells[nextColumn.Index];
便會出現錯誤訊息「因為程式無法認可或結束儲存格值的變更」
所以要改寫以下...(紅色+判斷)
        protected override bool ProcessDialogKey(System.Windows.Forms.Keys keyData)
        {
            //MessageBox.Show(this.CurrentCell.RowIndex.ToString());
            if (keyData == Keys.Tab || keyData == Keys.Enter)
            {
                if ((base.CurrentCell == null))
                {
                    return true;
                }
                DataGridViewColumn nextColumn = null;
                nextColumn = base.Columns.GetNextColumn(base.Columns[base.CurrentCell.ColumnIndex], DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly);
                if ((nextColumn != null))
                {
                    if(this.CurrentCell.IsInEditMode)
                        //當驗證沒過時, Coding部份為e.cancel=true, 使用這個方式就不會出錯了!
                        return base.ProcessDialogKey(Keys.Tab); 
                    else
                        base.CurrentCell = base.Rows[base.CurrentCell.RowIndex].Cells[nextColumn.Index];

                }
                else
                {
                    nextColumn = base.Columns.GetFirstColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly);
                    if ((base.CurrentCell.RowIndex + 1) == base.Rows.Count)
                    {
                        base.CurrentCell = base.Rows[0].Cells[nextColumn.Index];
                    }
                    else
                    {
                        if (this.CurrentCell.IsInEditMode)
                            //當驗證沒過時, Coding部份為e.cancel=true, 使用這個方式就不會出錯了!
                            return base.ProcessDialogKey(Keys.Tab); 
                        else
                            base.CurrentCell = base.Rows[base.CurrentCell.RowIndex + 1].Cells[nextColumn.Index];
                    }
                }
                //MessageBox.Show(this.CurrentCell.RowIndex.ToString());
                return true;
            }
            return base.ProcessDialogKey(keyData);
        }

參考:
[C#]DataGridView欄位驗證只能是數字且不能為空白
DataGridView.Rows.Clear() raise exception 
You received exception message Exception.InvalidOperation "Operation did not succeed because the program cannot commit or quit a cell value change." . If this DataGridView cell is in edit mode, you have to end/submit edit and then continue.

DataGridView 控制項 (Windows Form)

2013年8月8日 星期四

[技巧] DataGridViewComboBoxCell 取得 Value 的值

程式碼:
                DataGridView1.AutoGenerateColumns = False
                Dim cmb As New DataGridViewComboBoxColumn()
                cmb.HeaderText = "供應商簡稱"
                cmb.Name = "供應商簡稱"
                cmb.DataPropertyName = "供應商別"
                cmb.DisplayMember = "供應商簡稱"
                cmb.ValueMember = "供應商編號"
                cmb.DataSource = dt供應商
                DataGridView1.Columns.Insert(4, cmb)

原因:
假設某個Cell的 DisplayValue 為 "男", Value 為 "1"
當我們取用 DataGridView1(x,y).Value 時,
則其值為 ValueMember "1"
當我們要取值為男時為如何?

解決:
DataGridView1(col, row).FormattedValue.ToString

參考:
Getting Selected Text of combobox in datagridview
How to get the TEXT of Datagridview Combobox selected item?
DataGridView 控制項 (Windows Form)
請問DataGridViewComboBoxColumn 要如何取到改變selecteditem 後的值或文字

ProcessCmdKey方法让DataGridView按Enter回车键转到下一列的格
(讓ComboBoxColumn在下拉選項時, 解決出現二種模式...)

2013年8月7日 星期三

[除錯] 因為它會產生對 SetCurrentCellAddressCore 函式的可重新進入呼叫

問題:
Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore

例子:
我在DataGridView的CellEnter事件
寫入以下的CODE:「DataGridView1.CurrentCell = DataGridView1(0,0)」
當進入(0,0)時, 因觸發CellEnter事件, 又將CurrentCell = (0,0), 又再次觸發事件
因此形成一個無窮迴圈
datagridview中CellValidating中出现无限循环

參考:
UI开发时, UI消息处理过程混乱的解决方法
Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore function
RowLeave Event - Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore function
DataGridView 控制項 (Windows Form)

2013年5月17日 星期五

[技巧] DataGridView 當 ReadOnly = True 則跳下一欄位... & 類似VBA的TabStop功能...


用途:
DataGridView 遇到 ReadOnly 則跳過... (不停留 StopTab) 加強版
當設置某些欄位設置 CellStop ,則按 Enter/Tab 時直接跳過
但當用滑鼠點選時依然可以編輯,因為其 ReadOnly = False
如粉紅標記處

程式:
   Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
        '當按enter鍵時 執行tab鍵 -> 實現換行 '不過若是button鍵 就不能tab喔 應該是要Enter事件
        If keyData = Keys.Enter Then
            If Me.ActiveControl.Name = "DataGridView1" Then
                    Return SelectNextCell() 
            End If
        End If

        If keyData = Keys.Tab Then
            If Me.ActiveControl.Name = "DataGridView1" Then
                    Return SelectNextCell() 
            End If
        End If

        Return MyBase.ProcessCmdKey(msg, keyData)
    End Function

    Public Function SelectNextCell() As Boolean
        Dim row As Integer = DataGridView1.CurrentCell.RowIndex
        Dim column As Integer = DataGridView1.CurrentCell.ColumnIndex
        Dim startingCell As DataGridViewCell = DataGridView1.CurrentCell

        Do
            column += 1
            If column = DataGridView1.Columns.Count Then
                column = 0
                row += 1
            End If
            If row = DataGridView1.Rows.Count Then
                row = 0
            End If
         Loop While (CellStop.IndexOf(DataGridView1.Columns(column).Name) <> -1 _
                    OrElse DataGridView1.Columns(column).Visible = False OrElse DataGridView1(column, row).ReadOnly = True) AndAlso DataGridView1(column, row) IsNot startingCell

        If DataGridView1(column, row) Is startingCell Then
            Return False
        End If
        DataGridView1.CurrentCell = DataGridView1(column, row)
        Return True
    End Function

Dim CellStop As New ArrayList()
Private Sub DataGridView1_SelectionChanged(ByVal sender As Object, ByVal e As
        Me.CellStop.Clear()
        If Me.DataGridView1.CurrentRow.Cells("產品編號").Value.ToString.Split("-")(0) = "0" Then
            Me.CellStop.Add("牌價編號")
            Me.CellStop.Remove("尺寸規格名稱")
            Me.CellStop.Remove("材質全名")
        Else
            Me.CellStop.Remove("牌價編號")
            Me.CellStop.Add("尺寸規格名稱")
            Me.CellStop.Add("材質全名")
        End If
End Sub

=========================
備註:
1.
紫色標記處,為避免發生 "無法將目前的儲存格設定為不可見的儲存格" 的錯誤。

 2.
DataGridView 覆寫 ProcessDialogKey 及 ProcessDataGridViewKey 並成一個元件。
而黃色標記部份,是為了防止在編輯狀態下鍵入 Tab(Right / Left) 鍵 ,
避免在 ComBoBoxCell 時,在選擇期間鍵入此三鍵,而產生最左邊的RowHead
其三角形變成(並一直處於)編輯狀態(筆的形狀)...


Public Class mydgv
    Inherits DataGridView
    <System.Security.Permissions.UIPermission( _
        System.Security.Permissions.SecurityAction.LinkDemand, _
        Window:=System.Security.Permissions.UIPermissionWindow.AllWindows)> _
    Protected Overrides Function ProcessDialogKey( _
        ByVal keyData As Keys) As Boolean

        ' Extract the key code from the key value.
        Dim key As Keys = keyData And Keys.KeyCode

        ' Handle the ENTER key as if it were a RIGHT ARROW key.
        If key = Keys.Enter Then
            Return Me.ProcessRightKey(keyData)
        End If

        If (key = Keys.Tab) AndAlso CurrentCell.IsInEditMode Then
            Return False
        End If

        Return MyBase.ProcessDialogKey(keyData)
    End Function

    <System.Security.Permissions.SecurityPermission( _
        System.Security.Permissions.SecurityAction.LinkDemand, Flags:= _
        System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)> _
    Protected Overrides Function ProcessDataGridViewKey( _
        ByVal e As System.Windows.Forms.KeyEventArgs) As Boolean

        ' Handle the ENTER key as if it were a RIGHT ARROW key.
        If e.KeyCode = Keys.Enter Then
            Return Me.ProcessRightKey(e.KeyData)
        End If

        If (e.KeyCode = Keys.Left OrElse e.KeyCode = Keys.Right) AndAlso CurrentCell.IsInEditMode Then
            Return False
        End If

        Return MyBase.ProcessDataGridViewKey(e)
    End Function
End Class

[C#]
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace System.Windows.Forms
{
  class MyDataGridView : DataGridView
  {
    protected override bool ProcessDialogKey(Keys keyData)
    {
      if (keyData == Keys.Enter || keyData == Keys.Tab)
      {
        MyProcessTabKey(Keys.Tab);
        return true;
      }
      return base.ProcessDialogKey(keyData);
    }

    protected override bool ProcessDataGridViewKey(KeyEventArgs e)
    {
      if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Tab)
      {
        MyProcessTabKey(Keys.Tab);
        return true;
      }
      return base.ProcessDataGridViewKey(e);
    }

    protected bool MyProcessTabKey(Keys keyData)
    {
      bool retValue = base.ProcessTabKey(Keys.Tab);
      while (this.CurrentCell.ReadOnly)
      {
        retValue = base.ProcessTabKey(Keys.Tab);
      }
      return retValue;
    }
  }
}

參考:
鍵盤輸入的運作方式
DataGridView.ProcessDialogKey 方法
DataGridView.ProcessDataGridViewKey 方法
Control.SelectNextControl 方法
Control.GetNextControl 方法

DataGridView 编辑回车事件
跳到某一格...
.Net 2.0 DataGridView中键盘事件处理方法
DataGridView检查当前单元格是否处于编辑状态
Bypass read only cells in DataGridView when pressing TAB key
C# Enter轉Tab,讓MultiLine可換行
Up/Down - Arrow function
WM_KEYDOWN message
DataGridView 控制項 (Windows Form)

[C#]DataGridViewのCell移動をEnterで
DataGridViewでEnterキーを押すと隣のセルにフォーカスが移動されるようにする
svn/ trunk/ ExtControls/ 測試專案/ MyDataGridview.cs
Bypass read only cells in DatagridView when pressing TAB key (good)
关于DataGridView中键盘输入时的单元格跳转
svn/ trunk/ PT.Component/ DataGridView.cs
C#的dataGridView控件實現回車右移控制
ProcessCmdKey方法让DataGridView按Enter回车键转到下一列的格

How catch Enter Key on EndEdit of Datagridview
DataGridView.ProcessDataGridViewKey 方法

2013年5月6日 星期一

[技巧] DataGridViewComboBoxColumn 資料繫結(數據綁定) 驗證(判斷)值是否為繫結內的值 + 可手動輸入(自動篩選)

簡述:
DataGridViewComboBoxColumn 來源為資料庫dt (OR 自定義的DataTable)


Dim columnProvider As New DataGridViewComboBoxColumn()
        columnProvider.HeaderText = "供應商"
        columnProvider.Name = "供應商"
        columnProvider.DataPropertyName = "供應商編號"
        Dim graphics = CreateGraphics()

        columnProvider.DropDownWidth = (From width In (From item As DataRow In dt供應商.Rows _
                                                  Select Convert.ToInt32(graphics.MeasureString(item("供應商簡稱").ToString, Font).Width)) _
                                                  Select width).Max

        columnProvider.DataSource = dt供應商
        columnProvider.DisplayMember = "供應商簡稱"
        columnProvider.ValueMember = "供應商編號"


目的:
讓使用者可透過 "以下" 來篩選資料,但不可以為繫結資料外的值!


Private Sub DataGridView1_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing


     If TypeOf e.Control Is DataGridViewComboBoxEditingControl Then
            CType(e.Control, ComboBox).DropDownStyle = ComboBoxStyle.DropDown
            CType(e.Control, ComboBox).AutoCompleteSource = AutoCompleteSource.ListItems
            CType(e.Control, ComboBox).AutoCompleteMode = AutoCompleteMode.SuggestAppend

     End If
End Sub


程式: 因為想要把"需要判斷欄位"寫在同一個Sub,因此依這個來解決比較好閱讀!

    Private Sub DataGridView1_CellValidating(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValidatingEventArgs) Handles DataGridView1.CellValidating
        If DataGridView1.Columns(e.ColumnIndex).ReadOnly = True Then
            Exit Sub
        End If

        Dim grid As DataGridView = CType(sender, DataGridView)
        grid.Rows(e.RowIndex).ErrorText = ""

        If grid.Columns(e.ColumnIndex).Name = "供應商" Then
            '判斷是否為dt供應商內的值
            Dim num As Integer = 0
            For Each dr As DataRow In dt供應商.Rows
                If grid.Rows(e.RowIndex).Cells("供應商").EditedFormattedValue.ToString.Trim = dr("供應商簡稱").ToString.Trim Then
                    'MsgBox(dr("供應商簡稱").ToString.Trim)
                    num += 1
                    Exit For
                End If
            Next

            If num = 0 Then

                DataGridView1.Rows(e.RowIndex).ErrorText = _
                "不允許自行輸入, 請重新選擇!!"

                MsgBox("不允許自行輸入, 請重新選擇!!")
                e.Cancel = True
            End If
        End If
    End Sub

另解(1):  透過 CType(sender, ComboBox).SelectedIndex(SelectedItem/SelectedText,etc...) 來判斷!
DataGridViewComboBoxColumn 實現 SelectedIndexChanged 事件
How to get the valuemember from a DataGridViewComboBoxCell
Getting the Selected Value of Combo Box in DataGridView

另解(2):
System.ArgumentException:DataGridViewComboBoxCell 值無效 (2) 之 解決(二)


參考:
DataGridViewComboBoxCell.GetFormattedValue 方法
get value of combobox columns valuemember's value in DataGridView
實作 DataGridViewDropDownColumn
datagridview的combobox控件的添加
真正的DataGridViewComboBoxColumn
DataGridView 控制項 (Windows Form)

DataGridViewComboBoxColumn 可以让用户输入并自动匹配的选项的问题
你指定了ComboBox的DisplayMember和ValueMember后,会按你输入的ValueMember来匹配的,如果输入的如果你说的管理员,它在valueMember中不存在,所以不会选中.这样的话和你设置的就矛盾了,所以应该换种思路,不一定要用comboBox,可以把当前编辑的当元格转换成TextBox,然后在TextBoxChanged里面写,至于下拉列表可以用一个listview来显示,只要把它显示在TextBox的下端坐标值即可.那样根据输入的值,listview自动找匹配的供用户自己选择

ProcessCmdKey方法让DataGridView按Enter回车键转到下一列的格
(讓ComboBoxColumn在下拉選項時, 解決出現二種模式...)

2013年5月2日 星期四

[除錯] 並未將物件參考設定為物件的執行個體 DataGridViewComboBox [debug]

錯誤:
DataGridViewComboBox
並未將物件參考設定為物件的執行個體

程式:

            For Each dgvr As DataGridViewRow In DataGridView1.Rows
                'If dgvr.Index = DataGridView1.RowCount - 1 Then
                '    Exit For
                'End If
                'If dgvr.IsNewRow Then
                '    MsgBox("HAHA")
                '    Exit For
                'End If
                MsgBox(dgvr.Cells("供應商").Value.ToString.Trim)
            Next

解決:
因為 AllowUserToAddRows = True
所以 DGV 會自動 NewRow 出來

而 NewRow 在 for-loop 裡也會算作一份(index)
但實質上是 Nothing 的資料型態
當 loop 到 NewRow 時,便會發生如圖的錯誤

因此在 for-loop 時,要排除掉
可利用黃色方法或綠色方法

DataGridView 控制項 (Windows Form)

2013年4月26日 星期五

[技巧] DataGridView 驗證欄位的資料型態 以及 是否空白

程式:

    Private Sub DataGridView1_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit

        'DataGridView1.Rows(e.RowIndex).ErrorText = String.Empty
    End Sub

Private Sub DataGridView1_CellValidating(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValidatingEventArgs) Handles DataGridView1.CellValidating

        If e.ColumnIndex >= 10 AndAlso e.ColumnIndex <= 19 Then
            Exit Sub
        End If

        Dim newInteger As Integer
        Dim newDeciaml As Decimal

        Dim grid As DataGridView = CType(sender, DataGridView)
        grid.Rows(e.RowIndex).ErrorText = ""

        If String.IsNullOrEmpty(e.FormattedValue.ToString) Then
            DataGridView1.Rows(e.RowIndex).ErrorText = _
            "不允許空白!!"
            MsgBox("不允許空白")
            e.Cancel = True
        Else If grid.Columns(e.ColumnIndex).Name = "新增次數" OrElse grid.Columns(e.ColumnIndex).Name = "序號" _

           OrElse grid.Columns(e.ColumnIndex).Name = "項次" Then
            If Not Integer.TryParse(e.FormattedValue.ToString(), newInteger) _
                OrElse newInteger < 0 Then
                DataGridView1.Rows(e.RowIndex).ErrorText = _
                "只允許Integer!!"
                MsgBox("只允許Integer")
                e.Cancel = True
            End If
        ElseIf grid.Columns(e.ColumnIndex).Name = "金額" Then
            If Not Decimal.TryParse(e.FormattedValue.ToString(), newDeciaml) Then
                DataGridView1.Rows(e.RowIndex).ErrorText = _
                "只允許Decimal!!"
                MsgBox("只允許Decimal")
                e.Cancel = True
            End If
        End If

    End Sub

參考:
DataGridView: why is CellValidating firing as the grid is filling?
DataGridView.CellValidating 事件,確定使用者只輸入正整數。
DataGridView中数据输入验证
c# DataGridView中的单元格中只能输入数字的解决方法
C#如何在DataGridView控件中验证数据输入
DataGridViews, DataBinding and non validating cell values
[C#]DataGridView欄位驗證只能是數字且不能為空白
WinForm中DataGridView验证单元格输入的是数字
[ADO.NET][WinForm] 限制 DataGridView 輸入字元
DataGridView 控制項 (Windows Form)

判斷是否為數字、整數的正則表達式方法
C#检测字符串是否为正整数

[技巧] DataGridView 遇到 ReadOnly 則跳過... (不停留 StopTab)


    Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
        If keyData = Keys.Enter Then
            If Me.ActiveControl.Name = "DataGridView1" Then
                If CType(Me.ActiveControl, DataGridView).CurrentCell.ReadOnly = True Then
                    SelectNextCell()
                    Return True
                End If
            End If

            'Return MyBase.ProcessCmdKey(msg, keyData)
            SendKeys.Send(vbTab)
            Return True
        End If

        If keyData = Keys.Tab Then
            If Me.ActiveControl.Name = "DataGridView1" Then
                If CType(Me.ActiveControl, DataGridView).CurrentCell.ReadOnly = True Then
                    SelectNextCell() 'SendKeys.Send(Keys.Enter)
                    Return True
                End If
            End If

            Return MyBase.ProcessCmdKey(msg, keyData)
            'SendKeys.Send(vbTab)
            Return True
        End If

        Return MyBase.ProcessCmdKey(msg, keyData)
    End Function


    Public Function SelectNextCell() As Boolean
        Dim row As Integer = DataGridView1.CurrentCell.RowIndex
        Dim column As Integer = DataGridView1.CurrentCell.ColumnIndex
        Dim startingCell As DataGridViewCell = DataGridView1.CurrentCell

        Do
            column += 1
            If column = DataGridView1.Columns.Count Then
                column = 0
                row += 1
            End If
            If row = DataGridView1.Rows.Count Then
                row = 0
            End If
        Loop While DataGridView1(column, row).ReadOnly = True AndAlso DataGridView1(column, row) IsNot startingCell
'Loop While (DataGridView1.Columns(column).Visible = False OrElse DataGridView1(column, row).ReadOnly = True) AndAlso DataGridView1(column, row) IsNot startingCell


        If DataGridView1(column, row) Is startingCell Then
            Return False
        End If

        '這邊要注意起啟的位置,如果Column(0)為ReadOnly,則起啟就設置如下註解! 
        DataGridView1.CurrentCell = DataGridView1(1, row) 'DataGridView1(0, row)


        '如果是要真的讓ReadOnly都直接下一行下一列,則如下的Code才最正確
        DataGridView1.CurrentCell = DataGridView1(column, row)
        Return True
    End Function

[C#]
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace System.Windows.Forms
{
  class MyDataGridView : DataGridView
  {
    protected override bool ProcessDialogKey(Keys keyData)
    {
      if (keyData == Keys.Enter || keyData == Keys.Tab)
      {
        MyProcessTabKey(Keys.Tab);
        return true;
      }
      return base.ProcessDialogKey(keyData);
    }

    protected override bool ProcessDataGridViewKey(KeyEventArgs e)
    {
      if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Tab)
      {
        MyProcessTabKey(Keys.Tab);
        return true;
      }
      return base.ProcessDataGridViewKey(e);
    }

    protected bool MyProcessTabKey(Keys keyData)
    {
      bool retValue = base.ProcessTabKey(Keys.Tab);
      while (this.CurrentCell.ReadOnly)
      {
        retValue = base.ProcessTabKey(Keys.Tab);
      }
      return retValue;
    }
  }
}

備註:
如粉紅標記部份,假設有某欄位的visible=false
則必須在加上條件判斷 "DataGridView1.Columns(column).Visible = False"
此時黃色標記部份即可移除 ,若不加上粉紅標記部份,又沒加上黃色標記部份
則會發生 "無法將目前的儲存格設定為不可見的儲存格" 的錯誤,因為把 DataGridView1.CurrentCell 指定為 Visible = False 的 Cell

參考:
鍵盤輸入的運作方式
DataGridView.ProcessDialogKey 方法
DataGridView.ProcessDataGridViewKey 方法
Control.SelectNextControl 方法
Control.GetNextControl 方法

DataGridView 编辑回车事件
跳到某一格...
.Net 2.0 DataGridView中键盘事件处理方法
Protected Overrides Function ProcessCmdKey 
還少了上下左右的判斷,有需要的自己改寫!
Tab to the next cell in a DataGridView
No Tab Stop DataGridView Column
HOW TO AVOID ENTERING READONLY CELLS ON A DATAGRIDVIEW
Bypass read only cells in DataGridView when pressing TAB key
C# Enter轉Tab,讓MultiLine可換行
Up/Down - Arrow function
WM_KEYDOWN message
DataGridView 控制項 (Windows Form)


[C#]DataGridViewのCell移動をEnterで
DataGridViewでEnterキーを押すと隣のセルにフォーカスが移動されるようにする
svn/ trunk/ ExtControls/ 測試專案/ MyDataGridview.cs
Bypass read only cells in DatagridView when pressing TAB key (good)
关于DataGridView中键盘输入时的单元格跳转
svn/ trunk/ PT.Component/ DataGridView.cs
C#的dataGridView控件實現回車右移控制
ProcessCmdKey方法让DataGridView按Enter回车键转到下一列的格

How catch Enter Key on EndEdit of Datagridview
DataGridView.ProcessDataGridViewKey 方法