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

コンボボックスを表示したデータグリッドビューの列に値が表示されない。

環境/言語:[OS : Windows 7 / 言語 : Visual Basic .NET / .NET Framework : 4]
分類:[.NET]

【解決したい問題】

趣味で取り組んでる活動の情報をMDBで管理しているのですが、デー
タグリッドビューに表示された値をコンボボックスにて変更できるよう
に改修しようとしています。
【DataGridViewの列にコンボボックスを表示する】(http://dobon.net/vb/dotnet/datagridview/datagridviewcomboboxcolumn.html)および
【DataGridViewのコンボボックスにユーザーが文字列を入力できるようにする】(http://dobon.net/vb/dotnet/datagridview/comboboxdropdownstyle.html)他を
参考にさせて頂いてるのですが、思った様に動作せず困っています。よ
ろしくお願いします。

コンボボックスを表示したデータグリッドビューの列に値が表示されな
いんです。

【DataGridViewの列にコンボボックスを表示する】では、データグリッ
ドビューへ情報を表示する際、DataTable経由で表示していますが、現行
プログラムではデータグリッドビューへ行追加しています。行追加を実
行している箇所が数多い事から、列追加部はなるべく触りたくないのが
本音です。

DataTable経由でないとコンボボックスを表示した列に値を表示する事は
できないのでしょうか?

以下のソースにてコマンドライン引数に、"1"を与えた時は"Week"列に値
を表示できるんですが、"2"を与えた時は"Week"が空白になってしまいま
す。

================
Public Class Form1

    Private DataGridView1 As New DataGridView

    Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load

        Me.Controls.Add(DataGridView1)
        DataGridView1.Location = Me.ClientRectangle.Location
        DataGridView1.Size = Me.ClientRectangle.Size
        DataGridView1.Anchor = AnchorStyles.Left + AnchorStyles.Right + AnchorStyles.Top + AnchorStyles.Bottom
        AddHandler DataGridView1.EditingControlShowing, AddressOf DataGridView1_EditingControlShowing
        AddHandler DataGridView1.CellValidating, AddressOf DataGridView1_CellValidating

        Call SetData()

        'DataGridViewComboBoxColumnを作成する
        Dim column As New DataGridViewComboBoxColumn()
        'ComboBoxのリストに表示する項目を設定する
        column.Items.Add("日曜日")
        column.Items.Add("月曜日")
        column.Items.Add("火曜日")
        column.Items.Add("水曜日")
        column.Items.Add("木曜日")
        column.Items.Add("金曜日")
        column.Items.Add("土曜日")
        '"Week"列にバインドされているデータを表示する
        column.DataPropertyName = "Week"
        '"Week"列の代わりにComboBox列を表示する
        DataGridView1.Columns.Insert(DataGridView1.Columns("Week").Index, column)
        DataGridView1.Columns.Remove("Week")
        column.Name = "Week"

        column.DisplayStyleForCurrentCellOnly = True

    End Sub

    'EditingControlShowingイベントハンドラ
    Private Sub DataGridView1_EditingControlShowing(ByVal sender As Object, _
            ByVal e As DataGridViewEditingControlShowingEventArgs) _
            'Handles DataGridView1.EditingControlShowing
        If TypeOf e.Control Is DataGridViewComboBoxEditingControl Then
            '該当する列か調べる
            Dim dgv As DataGridView = CType(sender, DataGridView)
            'If dgv.CurrentCell.OwningColumn.Name = "ComboBox" Then
            If dgv.CurrentCell.OwningColumn.Name = "Week" Then
                '編集のために表示されているコントロールを取得
                Dim cb As DataGridViewComboBoxEditingControl = _
                    CType(e.Control, DataGridViewComboBoxEditingControl)
                cb.DropDownStyle = ComboBoxStyle.DropDown
            End If
        End If
    End Sub

    'CellValidatingイベントハンドラ
    Private Sub DataGridView1_CellValidating(ByVal sender As Object, _
            ByVal e As DataGridViewCellValidatingEventArgs) _
            'Handles DataGridView1.CellValidating
        Dim dgv As DataGridView = CType(sender, DataGridView)
        '該当する列か調べる
        'If dgv.Columns(e.ColumnIndex).Name = "ComboBox" AndAlso _
        If dgv.Columns(e.ColumnIndex).Name = "Week" AndAlso _
            TypeOf dgv.Columns(e.ColumnIndex) Is DataGridViewComboBoxColumn Then
            Dim cbc As DataGridViewComboBoxColumn = _
                CType(dgv.Columns(e.ColumnIndex), DataGridViewComboBoxColumn)
            'コンボボックスの項目に追加する
            If Not cbc.Items.Contains(e.FormattedValue) Then
                cbc.Items.Add(e.FormattedValue)
            End If
            'セルの値を設定しないと、元に戻ってしまう
            dgv(e.ColumnIndex, e.RowIndex).Value = e.FormattedValue
        End If
    End Sub

    Private Sub SetData()

        Select Case My.Application.CommandLineArgs(0)
            Case "1"
                'Week列のあるDataTableを作成する
                Dim dt As New DataTable()
                dt.Columns.Add("Date", GetType(String))
                dt.Columns.Add("Week", GetType(String))
                dt.Columns.Add("Time", GetType(String))
                dt.Rows.Add("8/25", "日曜日", "朝")
                dt.Rows.Add("8/26", "月曜日", "昼")
                dt.Rows.Add("8/27", "火曜日", "晩")
                'DataGridViewにデータソースを設定する
                DataGridView1.DataSource = dt
            Case "2"
                DataGridView1.Columns.Add("Date", "Date")
                DataGridView1.Columns.Add("Week", "Week")
                DataGridView1.Columns.Add("Time", "Time")
                DataGridView1.Rows.Add("8/25", "日曜日", "朝")
                DataGridView1.Rows.Add("8/26", "月曜日", "昼")
                DataGridView1.Rows.Add("8/27", "火曜日", "晩")
        End Select

        'DataGridView1にユーザーが新しい行を追加できないようにする
        DataGridView1.AllowUserToAddRows = False

        'DataGridView1の行をユーザーが削除できないようにする
        DataGridView1.AllowUserToDeleteRows = False

    End Sub

End Class
================
添付ファイル: Test03.jpg (54 KB)
おはようございます。


DataTableと連携する場合はDataGridViewはまぁデータと無関係な覗き窓のようなものなので
単にそこから列を消してもデータ側に何の影響もありませんが、
データ連携せずに使う場合は列定義が列の情報と直接関係するので、
DataGridView1.Columns.Remove("Week")として列を消してしまえばその列用にセットされているデータは当然消えます。

今のコードのままでどうしてもすりかえたいという場合は、
列を追加した後、元の列をRemoveする前にデータを新しい列の方へコピーする必要があります。
DataGridView1.Columns.Insert(DataGridView1.Columns("Week").Index, column)
For Each r As DataGridViewRow In DataGridView1.Rows
    r.Cells(column.Index).Value = r.Cells(DataGridView1.Columns("Week").Index).Value
Next
DataGridView1.Columns.Remove("Week")
 ※なお、よそと連携していない場合には
  column.DataPropertyName = "Week"
  はそもそも無意味です。
  (すり替えを行っていない他の2列には、このプロパティには何も入っていないと思います。)


ところで、
現在
DataGridView1.Columns.Add("Week", "Week")
としている部分ですが…
SetDataで一旦目的と違う形の列を作っておいて後からコンボボックスタイプにすりかえようとしている目的は何でしょうか?
DataGridView1.Columns.Addのもうひとつのオーバーロードを使えば定義した列情報を渡せるので、
最初から
Dim column As New DataGridViewComboBoxColumn()
column.Name = "Week"
column.Items.Add("日曜日")
column.Items.Add("月曜日")
column.Items.Add("火曜日")
column.Items.Add("水曜日")
column.Items.Add("木曜日")
column.Items.Add("金曜日")
column.Items.Add("土曜日")
DataGridView1.Columns.Add(column)
としてコンボボックスタイプのものを作れます。



ついでに…
「掲示板アップ用の仮プログラムだから」だと思いたいですが、
コマンドライン引数が1の際にはデータの方だけ列を作ってDataGridViewには列を作っていない点が気になります。
列の定義がない状態で連携するオブジェクトを渡した際にDataGridViewが自動的に面倒見て列定義を作ってくれているだけですので、
まともに日常使用するプログラムを作る場合には「作らないでよいもの」とは考えない方がよいでしょう。

本来はどちらの場合でもちゃんとスタイル等を整える意味でDataGridView側の列の定義が必要と考えた方がよいと思います。
(緊急で作る何かのチェック用プログラムの場合はともかく。)
とん。さん、早速の回答有難うございます。

>列を消してしまえばその列用にセットされているデータは当然消えます。
あまりに当然過ぎるご指摘、お恥ずかしい限りです。DataTable経由で
値を設定する場合に、セル値の転送が不要なためにウッカリしていまし
た。取り合えずテスト用ソースへ反映して動作を確認しました。

>SetDataで一旦目的と違う形の列を作っておいて後からコンボボック
>スタイプにすりかえようとしている目的は何でしょうか?
特に考えがあってそうしてる訳でなく、「掲示板アップ用の仮プログラ
ムだから」と言う理由から、参考にした【DataGridViewの列にコンボボ
ックスを表示する】に出来る限り手を入れたくなかっただけです。

>コマンドライン引数が1の際にはデータの方だけ列を作ってDataGridView
>には列を作っていない点が気になります。
これも上記と同様です。
解決済み!

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