DOBON.NET DOBON.NETプログラミング掲示板過去ログ

DataGridViewTextBoxEditingControlのKeyDownイベント処理

環境/言語:[OS : Windows Vista Home Premium / 言語 : C# / .NET Framework : 2.0]
分類:[.NET]

【解決したい問題】

DataGridViewで編集を行うとき、DataGridViewTextBoxEditingControlのイベ
ントで、Enter, Up, Down, Left, RightなどのKeyDownを補足しようと思って
います。これらの方向キーを押したときの処理はプログラムで行い、通常の
カーソル移動などの動作が発生するのを抑制したいと思っています。

しかし、このDataGridViewTextBoxEditingControlというテキストボックスで
は、これらのキーではKeyDownイベントが発生しません。

【解決するために何をしたか】

http://dobon.net/vb/dotnet/control/btndetectarraykey.html を参考にして、
上記のコントロールに次のようなPreviewKeyDownイベントハンドラーを設定し
ました。

private void tbox_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
    switch (e.KeyCode)
    {
        case Keys.Up:
        case Keys.Left:
        case Keys.Right:
        case Keys.Down:
            MessageBox.Show("Up, Down等のキー"); // テスト用
            e.IsInputKey = true;
            break;
    }
}

MessageBoxの表示で、この段階の捕捉できていることは確認できました。これ
で、Up、Leftキーなどにも普通のKeyDownイベントが発生するものと想像してい
たのですが、そうはならず、普通のUpキーやLeftキーの動作をしてしまいます。

【追加事項】

DataGridViewTextBoxEditingControlで、方向キーなどを押したとき、その処理
をプログラムで行い、e.Handled = trueのような設定をして、通常のカーソル
移動などの動作が発生するのを抑制するにはどうしたら良いでしょうか。
こんにちは。

こんな感じはどうでしょうか?

protected override void OnEditingControlShowing(DataGridViewEditingControlShowingEventArgs e) {
if (e.Control is TextBox) {
TextBox textBox = (TextBox)e.Control;
textBox.KeyPress += new KeyPressEventHandler(textBox_KeyPress);
base.OnEditingControlShowing(e);
}
}

void textBox_KeyPress(object sender, KeyPressEventArgs e) {
ここで処理する
}
# 全然試してないので、外れていたら申し訳ないですが

こちらのTipsを参考にしてはいかがでしょうか
http://dobon.net/vb/dotnet/datagridview/maskedtextboxcolumn.html

キーワード:EditingControlWantsInputKeyメソッド

手順
1.TextBoxEditingControlを継承して
  EditingControlWantsInputKeyメソッドを
  オーバーライドし、カーソル上下キーをDataGridViewに処理させないようにする
2.DataGridViewTextBoxCellを継承し、
  手順1.の自作編集コントロールを使うセルを自作する
3.DataGridViewTextBoxColumnを継承し、
  手順2.の自作セルを使うコラムを自作する
4.手順3.のコラムをDataGridViewで使う

私はDataGridViewで試したことはないですが、
GrapeCityのGcMultiRowで同様の処理を実装したことはあります

# 外れてたらすみません
2009/08/08(Sat) 01:22:10 編集(投稿者)

私のPCで試したところ、
EditingControlWantsInputKeyと
ProcessDataGridViewKeyの組み合わせで
うまくいきました
 
# コードがVBですがご了承下さいm(_ _)m
 
Public Class Form2
    Inherits Form
 
    Dim _dgv As New DataGridViewEX
 
    ' 画面初期表示
    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        Me.Text = Me.GetType.Name
 
        With Me._dgv
            .AutoGenerateColumns = False
            .Dock = DockStyle.Fill
            Me._helperAddColumn("列1")
            Me._helperAddColumn("列2")
            Me._helperAddColumn("列3")
            .DataSource = Me._helperCreateTable
        End With
 
        Me.Controls.Add(Me._dgv)
 
        MyBase.OnLoad(e)
    End Sub
 
    ' DataGridViewに列を追加する
    Private Sub _helperAddColumn(ByVal name As String)
        Dim col As New DataGridViewMyColumn
        col.DataPropertyName = name
        col.Name = name
        col.HeaderText = name
        Me._dgv.Columns.Add(col)
    End Sub
 
    ' データソースを作成する
    Private Function _helperCreateTable() As DataTable
        Dim dt As New DataTable
        dt.Columns.Add("列1", GetType(String))
        dt.Columns.Add("列2", GetType(String))
        dt.Columns.Add("列3", GetType(String))
        For i As Integer = 0 To 10
            dt.Rows.Add("データ1-" + i.ToString, "データ2-" + i.ToString, "データ3-" + i.ToString)
        Next
        Return dt
    End Function
 
End Class
 
 
' 編集モードでないときにカーソルキーを無効化するDataGridView
Public Class DataGridViewEX
    Inherits DataGridView
 
    Protected Overrides Function ProcessDataGridViewKey(ByVal e As System.Windows.Forms.KeyEventArgs) As Boolean
 
        Select Case e.KeyCode
            Case Keys.Up, Keys.Down, Keys.Left, Keys.Right
                ' カーソルキーは無効化
                Return True
            Case Else
                Return MyBase.ProcessDataGridViewKey(e)
        End Select
    End Function
 
End Class
 
 
' DataGridViewTextBoxCellを使うColumn
Public Class DataGridViewMyColumn
    Inherits DataGridViewTextBoxColumn
 
    Public Overrides Property CellTemplate() As System.Windows.Forms.DataGridViewCell
        Get
            Return New DataGridViewMyCell
        End Get
        Set(ByVal value As System.Windows.Forms.DataGridViewCell)
            MyBase.CellTemplate = value
        End Set
    End Property
 
End Class
 
 
' DataGridViewMyEditingControlを使うセル
Public Class DataGridViewMyCell
    Inherits DataGridViewTextBoxCell
 
    Public Overrides ReadOnly Property EditType() As System.Type
        Get
            Return GetType(DataGridViewMyEditingControl)
        End Get
    End Property
End Class
 
 
' カーソルキーをDataGridViewに送らない編集コントロール
Public Class DataGridViewMyEditingControl
    Inherits DataGridViewTextBoxEditingControl
 
    Public Overrides Function EditingControlWantsInputKey(ByVal keyData As System.Windows.Forms.Keys, _
            ByVal dataGridViewWantsInputKey As Boolean) As Boolean
        Select Case keyData
            Case Keys.Up, Keys.Down, Keys.Left, Keys.Right
                ' カーソルキーは編集コントロールが処理し、DataGridViewには送らない
                Return True
            Case Else
                Return MyBase.EditingControlWantsInputKey(keyData, dataGridViewWantsInputKey)
        End Select
    End Function
 
End Class
■No25162に返信(H.K.R.さんの記事)
> 2009/08/08(Sat) 01:22:10 編集(投稿者)
>
> 私のPCで試したところ、
> EditingControlWantsInputKeyと
> ProcessDataGridViewKeyの組み合わせで
> うまくいきました

どこかで、DataGridViewTextBoxEditingControlを継承するクラスを作る必要がありそうなことはうすうす気がついたのですが、そのクラスのオブジェクトをDataGridViewにどう渡すのか、悩ましい思いでした。

カラムのクラス、セルのクラス、そしてDataGridViewのクラスを少しずつ修正するんですね、その様子がよくわかりました。

これから実験してみます。結果の報告までには少し時間がかかると思います。
H.K.R.さんに教えてもらった方法でやってみました。

●方向キーなどは捕捉できるが、Enterキーが捕捉できない。

新しいDataGridViewTextBoxEditingControlの継承クラスを定義し、その中で
方向キー、PageUp、PageDown、Home、End、そしてEnterキーを要求しました。
継承クラスのKeyDownイベントでそれらのキーを捕捉できるようになったので
すが、ひとつだけ、Enterキーが捕捉できません。

?このテキストボックスのKeyDownイベントでEnterキーを捕捉することはでき
ないでしょうか。
お疲れ様です

以下の方法で試してみてください

1.編集モードの場合
 PageUp、PageDown、矢印キーは、EditingControlWantsInputKeyで捕捉する
 Enterキーは、PreviewKeyDownイベント(またはOnPreviewKeyDownメソッド)で捕捉する

2.編集モードでない場合
 PageUp、PageDown、矢印キー、Home、End、Enterキーを、ProcessDataGridViewKeyで捕捉する
H.K.R.さん、有難う御座います。

■No25223に返信(H.K.R.さんの記事)
> 以下の方法で試してみてください
>
> 1.編集モードの場合
>  PageUp、PageDown、矢印キーは、EditingControlWantsInputKeyで捕捉する
>  Enterキーは、PreviewKeyDownイベント(またはOnPreviewKeyDownメソッド)で捕捉する

PreviewKeyDownイベントを試してみました。たしかにEnterキーを捕捉するこ
とはできますが、その後のEnterキーの既定の動作を抑止することができませ
ん。KeyDownイベントではe.Handled=trueとして、キーの既定の動作を抑止で
きますが、PreviewKeyDownではそのようの処置ができません。むずかしいで
すね。
お疲れ様です

e.IsInputKey = True
で試してみてください
H.K.R.さん有難う。

■No25230に返信(H.K.R.さんの記事)
> e.IsInputKey = True
> で試してみてください

できました。PreviewKeyDownでe.IsInputKey= trueの設定だけをすると、KeyDownでEnterキーを捕捉できました。

手取り足取りしてもらわないと一歩もすすめない自分が情けなくなります。

それにしてもDataGridViewというのは複雑ですね。
1)KeyDownで方向キーやジャンプキーを捕捉するには、EditingControlWantsInputKeyをoverrideしなければならない。
2)また、KeyDowndeでEnterキーを捕捉するには、EditingControlWantsInputKeyのなかでEnterを指定に加えるとともに、PreviewKeyDownでe.IsInputkey=trueを設定してやらなければならない。

一応、当面の問題はクリアできました。ただし、今考えている機能全体を完成するには、さらに多くの問題を解決する事が必要なようです。

いままでFlexGridというMS以外のグリッドを使っていたのですが、vs2005から2008あるいは2010へのバージョンアップするときに、DataGridViewの方がバージョンアップが楽だろうとおもって乗換えを考えたのですが、いまになってちょっと怖気づいています。

どなたかのコメントがいただけたらと思い、もうしばらく解決済みのチェックをつけないでおきますので、よろしく。
お疲れ様です

> PreviewKeyDownでe.IsInputKey= trueの設定だけをすると、KeyDownでEnterキーを捕捉できました。
> 手取り足取りしてもらわないと一歩もすすめない自分が情けなくなります。
いえいえ、とんでもないです。スレッドの先頭のとんびさんのコードに書いてあります(^^

> 2)また、KeyDowndeでEnterキーを捕捉するには、EditingControlWantsInputKeyのなかでEnterを指定に加えるとともに、PreviewKeyDownでe.IsInputkey=trueを設定してやらなければならない。
EditingControlWantsInputKeyでEnterの指定は不要でした(私のPCで確認)

> DataGridViewの方がバージョンアップが楽だろうとおもって乗換えを考えたのですが、
私はFlexGridを触ったことがないので、コメントは他の方にお譲りします。

# GcMultiRowとDataGridViewはカスタムセルの作り方が似ているので、DataGridViewの知識は無駄にはならないです。
H.K.R.さん お付き合いいただいて有難う御座います。

この問題に限定する限り、一応問題解決です。
DataGridViewでちゃんとしたアプリケーションにするまでにはまだまだ道
が遠そうですが、がんばります。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板