DataGridViewのコンボボックスについて への返答

投稿で使用できる特殊コードの説明。(別タブで開きます。)
本名は入力しないようにしましょう。
投稿した後で削除するときに使うパスワードです。返答があった後は削除できません。
返答する人が目安にします。相手が小学生か社会人かで返答の仕方も変わります。
最初の投稿が質問の場合、質問者が解決時にチェックしてください。(以降も追加書き込み・返信は可能です。)
※「過去ログ」について書くときはその過去ログのURLも書いてください。

以下の返答は逆順(新しい順)に並んでいます。

投稿者 魔界の仮面弁士  (社会人) 投稿日時 2019/12/18 13:42:20
🔹 ドロップダウンセル (DataGridViewComboBoxCell) を使えば、
 行ごとに(というかセル単位で)ドロップダウンの内容を
 割り当てることができます。
🔸 ドロップダウン列 (DataGridViewComboBoxColumn) を使った場合、
 すべての列が同じ一覧を共有することになってしまいます。
🔹 列テンプレートが、テキスト列 (DataGridViewTextBoxColumnl) や
 ドロップダウン列(DataGridViewComboBoxColumn) 、あるいはそれ以外であったとしても、
 特定のセルだけのみを、別のセルタイプに置き換えることは可能です。
🔸 セル単位での設定が行われると「非共有行」となるため、共有行に比べて
 負荷が高くなりがちです。通常は気にするほどでもないと思いますが、
 データ量が非常に多いテーブルの場合は、仮想モードの併用も検討してみてください。


そしてるきおさんの例も私の例も、該当セルに対する DataGridViewComboBoxCell クラスの
インスタンスを操作することで実現しています。

るきおさんのコードでは、最初にドロップダウン列を設定しています。
これにより、該当列のすべての行がドロップダウンセルになるので、
データ型を DataGridViewComboBoxCell に DirectCast して操作しています。

一方、私のコードでは 0列目をテキストボックス列に設定しているため、
0 列目のすべての行がテキスト型のセルになっているのですが、
0 列目の 1 行目 2 行目のみ、ドロップダウンセルに差し替えるため、
新しい DataGridViewComboBoxCell インスタンスを作り、それをセットしています。

ちなみに、セル単位でのアクセスのためには、
 A:『DataGridView1.Rows(行).Cells(列)』
 B:『DataGridView1(列, 行)』
 C:『DataGridView1.Item(列, 行)』
のいずれの構文も使えます。

ドロップダウンされるデータ登録のために、るきおさんのコードでは
.Items.Add を使い、私のコードでは .DataSource を使っていますが、本質は同じことです。

殆どの列で同じ一覧を使い、特定の行だけで一覧を差し替えたいような場合は、
列全体に .DataSource を指定し、特定の行だけ別の .DataSource を設定しなおすと良いでしょう。


ただし同じドロップダウンに対して、.Items.Add と .DataSource を
同時に適用することは出来ませんので御注意ください。

たとえば、ドロップダウン列(DataGridViewComboBoxColumn)に対して、
.DataSource を設定していた場合、特定の行のドロップダウンだけを
.Items.Clear() したり .Items.Add することはできません。

全体は DataSource で設定し、一部の行だけは Items.Add を使いたい場合には
該当セルに DataGridViewComboBoxCell のインスタンスを割り当てなおすことも出来ます。

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    '  列全体に DataSource を割り当てています 
    Dim col As New DataGridViewComboBoxColumn() With {.Name = "col", .HeaderText = "さんぷる"}
col.DataSource = New String() { "マリキータ",  "るきお""魔界の仮面弁士" }
    dgv.Columns.Add(col)

    'テスト用に 10 行ほど追加 
    For r = 0 To 9
        dgv.Rows.Add()
    Next

    ' 列全体が DataSource 方式なら、一部の行(ここでは 0 行目)のみを 
    ' 別の DataSource にしても構いません 
    DirectCast(dgv(col.Index, 0), DataGridViewComboBoxCell).DataSource = New String() { "将棋",  "チェス""囲碁" }


    ' 列全体が DataSource 方式の場合、一部の行(ここでは 3 行目)のみを 
    '  .Items.Clear や .Items.Add することはできません 
    'DirectCast(dgv(col.Index, 3), DataGridViewComboBoxCell).Items.Clear() 

    ' ただし、DataGridViewComboBoxCell の新しいインスタンスをセットすれば、 
    ' 一部の行(ここでは 3 行目)に対して .Items 方式に切り替えることが出来ます 
    Dim comboBoxCell3 As New DataGridViewComboBoxCell()
    dgv(col.Index, 3) = comboBoxCell3
    comboBoxCell3.Items.Add("りんご")
    comboBoxCell3.Items.Add("バナナ")
    comboBoxCell3.Items.Add("ぶどう")
End Sub
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2019/12/18 09:34:35
サンプル。

Public Class Form1
    Private ds As New DataSet
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        dgv.RowCount = 4

        Dim fruit As New Dictionary(Of IntegerStringFrom {{0, ""}, {1, "🍎りんご"}, {2, "🍌バナナ"}, {3, "🍇ぶどう"}}
        Dim game As New Dictionary(Of IntegerStringFrom {{0, ""}, {1, "☖将棋"}, {2, "♔チェス"}, {3, "●囲碁"}}

        col2.DataSource = fruit.ToArray()
        col3.DataSource = game.ToArray()

        dgv("col1", 0).Value = "0行目"

        Dim cell01 As New DataGridViewComboBoxCell()
        cell01.ValueMember = "Key"
        cell01.DisplayMember = "Value"
        cell01.DataSource = fruit.ToArray()
        cell01.Value = 2
        dgv("col1", 1) = cell01

        Dim cell02 As New DataGridViewComboBoxCell()
        cell02.ValueMember = "Key"
        cell02.DisplayMember = "Value"
        cell02.DataSource = game.ToArray()
        cell02.Value = 2
        dgv("col1", 2) = cell02

        dgv("col1", 3).Value = "3行目"
    End Sub

#Region "実際にはデザイン時に設定しておく範囲ですが、説明のために記述しています"
    Private WithEvents dgv As DataGridView
    Private WithEvents col1 As DataGridViewTextBoxColumn
    Private WithEvents col2 As DataGridViewComboBoxColumn
    Private WithEvents col3 As DataGridViewComboBoxColumn
    Public Sub New()
        InitializeComponent()
        Padding = New Padding(8)
        dgv = New DataGridView() With {.Name = "dgv"}
        dgv.Dock = DockStyle.Fill
        Controls.Add(dgv)
        col1 = New DataGridViewTextBoxColumn() With {.Name = "col1"}
        col2 = New DataGridViewComboBoxColumn() With {.Name = "col2"}
        col3 = New DataGridViewComboBoxColumn() With {.Name = "col3"}
        col2.ValueMember = "Key"
        col2.DisplayMember = "Value"
        col3.ValueMember = "Key"
        col3.DisplayMember = "Value"
        dgv.Columns.AddRange(col1, col2, col3)
        dgv.EditMode = DataGridViewEditMode.EditOnEnter
        dgv.AllowUserToAddRows = False
    End Sub
#End Region
End Class
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2019/12/18 01:38:05
状況を再現するための情報の提示をお願いします。

テンプレートとしての DataGridViewComboBoxColumn をお使いでしょうか。
それともセル単位の DataGridViewComboBoxCell をお使いでしょうか。

また、 .DataSource への設定と .Items.Add での設定方法、どちらをご利用でしょうか。

もしも .DataSource を使っている場合、そこに何を渡していますか?
DataView / DataSet / DataTable を渡しているのか、
それとも List / 配列を渡しているのかなど…具体的な情報を述べた方が
回答がつきやすいかと思います。
投稿者 マリキータ  (社会人) 投稿日時 2019/12/17 23:02:19
るきお様

お教えくださり有り難うございます。
そのようなやり方があると学べました。

また、情報が少なく申し訳ありません。

エラーはコンボボックスの値に存在しませんという旨のえらーでしたが、現在は解決しています。

コンボボックスにはDBから取得したデータがバインドされており、別の列の値によってバインドしたデータの中から必要なもののみを表示したいです。

予めコンボボックスには必要なデータ(使う可能性のあるデータ)を用意しておき、コード列の値によってその中から必要なものだけ表示させたいです。

コード列の値は行ごとに違うので、コンボボックスに表示する(絞り混む)値は違いますが、現状としては複数行コンボボックスがある状態ですと、一つ変えるとすべて同じ中身になってしまいます


投稿者 るきお  (社会人) 投稿日時 2019/12/17 22:05:28
データバインドしないのならこのような感じでできますが、お役に立ちますか?

'▼列を定義 
DataGridView1.Columns.Add("Category""分類")
DataGridView1.Columns.Add(New DataGridViewComboBoxColumn With {.HeaderText = "項目"})


'▼1行目 
DataGridView1.Rows.Add("食べ物""りんご")
Dim comboBoxCell1 = DirectCast(DataGridView1.Rows(0).Cells(1), DataGridViewComboBoxCell)

comboBoxCell1.Items.Add("りんご")
comboBoxCell1.Items.Add("バナナ")
comboBoxCell1.Items.Add("ぶどう")

'▼2行目 
DataGridView1.Rows.Add("趣味""将棋")
Dim comboBoxCell2 = DirectCast(DataGridView1.Rows(1).Cells(1), DataGridViewComboBoxCell)

comboBoxCell2.Items.Add("将棋")
comboBoxCell2.Items.Add("チェス")
comboBoxCell2.Items.Add("囲碁")


現状のプログラムがどうなっていて、どんなエラーがでるのかを具体的に書いていただいたほうが、役に立つ回答が付きやすいですよ。
投稿者 マリキータ  (社会人) 投稿日時 2019/12/17 18:34:11
お世話になっております

お尋ねしたいことがあります。

DataGridViewのコンボボックスですが、複数行に別々のアイテムをインサートすることは可能なのでしょうか?

1行目に "りんご","バナナ","ぶどう"というアイテムが入ったコンボボックスを作成後、
2行目に "将棋","チェス","囲碁"というアイテムを設定しようとすると、エラーが出てしまいます。

なので、予めりんご~囲碁までをコンボボックスに挿入しておき、再度1行目と2行目で分けて
コンボボックスにアイテムを追加しようとすると、エラーは生じなくなりましたが1,2行目どちらの
コンボボックスも将棋~囲碁が挿入されてしまいます。

何卒よろしくお願いいたします