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 方法

沒有留言:

張貼留言