いつもお世話になっております。
私は今、データグリッドにコンボボックスを表示させていて、コンボボックス内にフォーカスがあるときに"←"キー押下でセルを左に移動させる処理を考えているのですが、どうもうまくいきません。
Protected Overrides Function ProcessCmdKeyを使って"←"キーをオーバーライドさせてセル移動も考えたのですが、入力途中で左前の文字に行こうとして"←"キーを押下すると、セル移動してしまいだめという状態です。
だれか分かる方がいましたらご教授お願いいたします。
コンボボックス側で入力開始から終了までフラグを
立てておき、フラグが立っている時は無視、立って
いない時は DataGrid に通知すれば…できるかなぁ(未確認)
特攻隊長まるるうさん、返答ありがとうございます。入力開始から終了フラグをたてるといいますと、どのようになるのでしょうか?入力開始、終了の判断というのはイベントとかですか?
開始、終了の判断ができるものがあれば教えていただけると幸いです。
データグリッドにコンボボックスを表示させる方法は独自のものですよね?
だったらコンボボックス側の仕様が分からないと何とも言えません。
DataGrid 側では編集の開始は DataGrid.ColumnStartedEditing メソッド
のオーバーロードされた2つの関数をオーバーライドすれば分かります。
編集の終了は…なんだろ?イベントかなぁ?
…でも既存の機能で『←』移動できますよね? DataGrid は。コンボボックス
側で何か作らないと出来ないと思いますよ?。
特攻隊長まるるうさん、早速の返答ありがとうございます。
http://dobon.net/vb/dotnet/samples/datagridcomboboxcolumn.html
コンボボックスは↑のサンプルをほぼそのまま活用しています。
>>…でも既存の機能で『←』移動できますよね?
既在の機能では、文字編集中に一つ前の文字とかに戻るのには”←”は移動できますが、1番左に移動しているときに”←”を押しても、左のセルには移動できません。
コンボボックス側で移動できる処理を加えなければいけないということですね。がんばって考えてみます。
いつもお世話になっております。表題の件ですが、いろいろ試してみたのですが、うまくいきません。
コンボボックス側の仕様は以下のようになっております。
このコンボボックスにキー押下時の処理を加えてあげればよいのでしょうか!?
初心者なもので、このような低レベルな質問になってしまいますが、分かる方がおりましたら、宜しくお願いいたします。
Imports System
Imports System.Data
Imports System.Windows.Forms
Imports System.Drawing
Public Class DataGridComboBoxColumn
Inherits DataGridTextAlignColumn
'Inherits DataGridTextBoxColumn
Private _comboBox As DataGridComboBox
Private _sorce As CurrencyManager
Private _rowNumber As Integer
Private _editing As Boolean
'/ <summary>
'/ DataGridComboBoxColumnのコンストラクタ
'/ </summary>
'/ <param name="dataSource">ComboBoxのDataSource</param>
'/ <param name="displayMember">ComboBoxのDisplayMember</param>
'/ <param name="valueMember">ComboBoxのValueMember</param>
Public Sub New(ByVal dataSource As DataView, _
ByVal displayMember As String, _
ByVal valueMember As String)
'初期設定
_sorce = Nothing
_editing = False
'DataGridComboBoxの作成
_comboBox = New DataGridComboBox
'ComboBoxの設定
_comboBox.DropDownStyle = ComboBoxStyle.DropDown
_comboBox.Visible = True
'データソースの設定
_comboBox.DataSource = dataSource
_comboBox.DisplayMember = displayMember
_comboBox.ValueMember = valueMember
'イベントハンドラ
AddHandler _comboBox.Leave, AddressOf _comboBox_Leave
AddHandler _comboBox.SelectionChangeCommitted, _
AddressOf _comboBox_SelectionChangeCommitted
'AddHandler _comboBox.TextChanged, AddressOf _comboBox_TextChanged
End Sub
'プロパティ
'/ <summary>
'/ 管理されている ComboBox コントロールを取得します。
'/ </summary>
Public ReadOnly Property ComboBox() As DataGridComboBox
Get
Return _comboBox
End Get
End Property
'ComboBoxからフォーカスが離れた
Private Sub _comboBox_Leave(ByVal sender As Object, _
ByVal e As EventArgs)
If _editing Then
'ComboBoxが編集中だったとき
_editing = False
'行の値を更新する
SetColumnValueAtRow(_sorce, _rowNumber, _
_comboBox.Text)
Invalidate()
End If
'ComboBoxを隠す
_comboBox.Visible = False
'DataGridのスクロールイベントを捕捉する
AddHandler DataGridTableStyle.DataGrid.Scroll, _
AddressOf DataGrid_Scroll
End Sub
'DataGridがスクロール
Private Sub DataGrid_Scroll(ByVal sender As Object, _
ByVal e As EventArgs)
'ComboBoxを消す
If _comboBox.Visible Then
_comboBox.Visible = False
End If
End Sub
'ComboBoxで選択した項目が変更されて、その変更がコミットされた
Private Sub _comboBox_SelectionChangeCommitted( _
ByVal sender As Object, ByVal e As EventArgs)
_editing = True
'DataGridに列が編集開始されたことを知らせる
MyBase.ColumnStartedEditing(CType(sender, Control))
End Sub
'行の最小の高さ
Protected Overrides Function GetMinimumHeight() As Integer
Return _comboBox.PreferredHeight
End Function
'ComboBoxをDataGridのControl.ControlCollectionに追加する
Protected Overrides Sub SetDataGridInColumn( _
ByVal value As DataGrid)
MyBase.SetDataGridInColumn(value)
_comboBox.Parent = CType(value, Control)
End Sub
'列が管理しているコントロールへのフォーカスを
'放棄する必要があることを列に通知
Protected Overrides Sub ConcedeFocus()
MyBase.ConcedeFocus()
_comboBox.Visible = False
End Sub
''編集するためにセルを準備する
Protected Overloads Overrides Sub Edit( _
ByVal source As CurrencyManager, _
ByVal rowNum As Integer, _
ByVal bounds As Rectangle, _
ByVal [readOnly] As Boolean, _
ByVal instantText As String, _
ByVal cellIsVisible As Boolean)
'基本クラスのEditを呼び出す
MyBase.Edit(source, rowNum, bounds, [readOnly], _
instantText, cellIsVisible)
'TextBoxを消す
Me.TextBox.Visible = False
'値の保存
_rowNumber = rowNum
_sorce = source
'表示させるComboBoxの設定をする
_comboBox.Bounds = bounds
_comboBox.RightToLeft = _
Me.DataGridTableStyle.DataGrid.RightToLeft
'非表示、読み取り専用のときは、ComboBoxを表示しない
If cellIsVisible AndAlso Not [readOnly] Then
'ComboBoxを表示
_comboBox.Visible = True
_comboBox.BringToFront()
_comboBox.Focus()
End If
'選択項目の変更
'ComboBoxを表示する前に行うと、
'新しい行で値を変更した時不都合が起きる
_comboBox.SelectedIndex = _
_comboBox.FindStringExact(Me.TextBox.Text)
'DataGridのスクロールイベントを捕捉する
AddHandler DataGridTableStyle.DataGrid.Scroll, _
AddressOf DataGrid_Scroll
End Sub
'編集プロシージャを完了する
Protected Overrides Function Commit( _
ByVal dataSource As CurrencyManager, _
ByVal rowNum As Integer) As Boolean
If _editing Then
'編集中のときは、rowNum行の値を設定する
_editing = False
SetColumnValueAtRow(dataSource, rowNum, _
_comboBox.Text)
End If
Return True
End Function
'指定した行の値を設定
Protected Overrides Sub SetColumnValueAtRow( _
ByVal source As CurrencyManager, _
ByVal rowNum As Integer, ByVal value As Object)
'ValueMemberの値を設定する
MyBase.SetColumnValueAtRow(source, rowNum, _
_comboBox.FindValueMember(value))
End Sub
'指定した行の値を取得
Protected Overrides Function GetColumnValueAtRow( _
ByVal source As CurrencyManager, _
ByVal rowNum As Integer) As Object
Dim val As Object = _
MyBase.GetColumnValueAtRow(source, rowNum)
'DisplayMemberの値を返す
Return _comboBox.FindDisplayMember(val)
End Function
End Class
Public Class DataGridComboBox
Inherits System.Windows.Forms.ComboBox
Private WM_KEYUP As Integer = &H101
Protected Overrides Sub WndProc( _
ByRef theMessage As System.Windows.Forms.Message)
'キー操作を無効にする()
If theMessage.Msg = WM_KEYUP Then
Return
End If
MyBase.WndProc(theMessage)
End Sub
'/ <summary>
'/ DisplayMemberからValueMemberの値を探す
'/ </summary>
'/ <param name="display">探すDisplayMember値</param>
'/ <returns>見つかったValueMember値</returns>
Public Function FindValueMember( _
ByVal display As Object) As Object
Dim dv As DataView = CType(DataSource, DataView)
Dim rowCount As Integer = dv.Count
'ループして探す
Dim disp As Object
Dim i As Integer
For i = 0 To rowCount - 1
disp = dv(i)(DisplayMember)
'見つかった時
If display.Equals(disp) Then
Return dv(i)(ValueMember)
End If
Next i
'見つからなかった時
Return DBNull.Value
End Function
'/ <summary>
'/ ValueMemberからDisplayMemberの値を探す
'/ </summary>
'/ <param name="value">探すValueMember値</param>
'/ <returns>見つかったDisplayMember値</returns>
Public Function FindDisplayMember( _
ByVal value As Object) As Object
Dim dv As DataView = CType(DataSource, DataView)
Dim rowCount As Integer = dv.Count
'ループして探す
Dim val As Object
Dim i As Integer
For i = 0 To rowCount - 1
val = dv(i)(ValueMember)
'見つかった時
If value.Equals(val) Then
Return dv(i)(DisplayMember)
End If
Next i
'見つからなかった時
Return DBNull.Value
End Function
End Class
ソースはリンク先で分かるから改造したとこだけ教えてくれる方が
有難かったかなぁ(^^;)…でないとオイラ…解析しなきゃいけないデショ?w
>初心者なもので、このような低レベルな質問になってしまいますが
『継承』の時点で低レベルじゃないよ?こーゆー書き方ってボクは嫌い。
ボクの回答基準は相手の『誠意』であり『レベル』じゃないのデス。
逆に相手が『初心者』ってゆー言葉を出したら全部答えなきゃならないのか?
それには疑問が残ります。
『初心者』っていっても幅がありますし、結局、相手の力量は書込みの内容から
判断しないといけません。こちらで判断できますし、寧ろこちらで判断すること
だと思ってます。自称『初心者』って意味無いし、鬱陶しい場合が多いのでボクは
嫌ってます。ボクがメインで回答を付けている場合はこの言葉を使わないように
しましょうw。機嫌を損ねます(爆)。…自分のやったことを見せれば他は必要無い
と思うんだけどね…。社交辞令の謙遜(?)も必要かにゃ…。回答者に『あなたなら
分かるはずだから答えて下さい!』と強要されている感じがして謙遜になってない
気がするんですよねぇ。『わたしは分かりません』と宣言されてるみたいにも感じ
ます。オイラだって分かるもののみ答えてたら3割程度しか答えられませんって(汗)。
ほとんどの回答はその場で考えてますからねぇ。質問者の問題なのにボクだけ考え
て、ボクだけ調べて…答えだけ盗まれるのはイヤナノ。
さて、ざっと解析しましたが、基本は
http://dobon.net/vb/dotnet/samples/datagridcomboboxcolumn.html
の DataGridComboBoxColumn(DataGridTextBoxColumn の継承)のままですよね?。
ただし、継承しているのは DataGridTextAlignColumn というユーザ定義の
クラス。たぶん
http://dobon.net/vb/dotnet/datagrid/aligncolumnheaderonly.html
↑これ?…こーゆー情報こそ省略されては困るんですが…(^^;)まぁ、…探しますけどね(TT)
改造した点は… DataGridTextAlignColumn の方は全く分からないけど、そのまま
使ってるとして、動作が変わってくる変更点として
_comboBox.DropDownStyle = ComboBoxStyle.DropDown
のユーザが入力可となってる所くらいですかねぇ。
2段階以上のユーザによる独自の継承をする場合はオーバーロードで動作が矛盾しない
ように気をつけて下さいね。…特にどっかのコピペの場合は十分に動作を確認して下さい。
DataGrid から DataGridTableStyle.GridColumnStyles 経由で DataGridTextBoxColumn
がどう動くかはあまり調べてないんだけど、Edit メソッドでコントロール _comboBox
を表示して編集。選択項目が変われば _comboBox_SelectionChangeCommitted イベント。
テキスト編集中は _editing フラグを立てて、編集終了時に Commit 。SetColumnValueAtRow で
指定行の更新ですね。それとフォーカス移動時の _comboBox_Leave イベント。この辺りが
データ編集の終了処理として関係しているわけです。
>いろいろ試してみたのですが、うまくいきません。
その『何を』『どう』試して『何が』上手くいかなかったかの情報が欲しい
んですが?(^^;)
ボクも『今』解析して『今』考えて『今』回答してるので、まいさんからの
情報が何もないと、最初から考えないといけないわけです。そこでまいさんの
試した内容が書き込まれていると参考に出来ます。ボクがもう一度試すのは
二度手間でしょ?。新しい動作のコーディングに関しては『質問者』はただの
『質問者』であってはいけないと思います。『回答者』の『協力者』でないと…。
『わたしには出来ませんのでどうにかして下さい』的な1から10までこちらで
考えないといけない質問なら、最初から回答する気はありませんので、ご了承
ください。
…まぁ、このコードだと DataGridComboBoxColumn クラスで例にならって
イベントコードの追加でしょうか。とりあえず _comboBox.KeyDown あたりが
無難でしょうね。ローカル変数に _comboBox を持ってるわけですから、これ
を使えばどういう状態なのか分かります。カーソル位置によって編集終了時
の処理を走らせて…でもそれだけだと移動が出来ませんね。…どうしますかねぇ。
とりあえず SendKeys.Send しちゃうのが一番修正が少ないように思います。
編集終了処理をしてコンボボックス隠した後(←隠さないと暴走の危険あり)
SendKeys.Send("{LEFT}")
か、タブを送っていいなら
SendKeys.Send("+{TAB}")
で _comboBox_Leave イベントが走って確定してくれますね。
確実にいくなら DataGrid のハンドル使って API の SendMessage かなぁ。
自分自身に送るなら Control.WndProc とか使えそうだけど…うーむ。
…そこそこ動くコードは書いたけど考え中…。とりあえず上に書いたような
方法を調べてコーディングしてみて下さい。
ツイート | ![]() |