none
DataGridViewでの複数列ComboBox(Access風) RRS feed

  • 質問

  • ジョウジと申します、初めての投稿です。

    VB2008とSQL2008を使用し開発しております、

    DataGridViewで複数列表示のAccess風のコンボボックスを

    実現したいと思います、色々ネットで調べたところ…

    下記リンクのホームページで問題内容に近い例を見つけました。

    http://www.codeproject.com/KB/cpp/DropDownListColumn.aspx

    ダウンロードし実行しましたが、経験があさいせいか、なかなか解決できません。

    上記サイトのソースコードを修正し実現できればと思っています。

    もしくは初心者でも分かりやすいサイトなど、いろいろな情報お待ちしております、

    ご教授宜しくお願います。

     

     

    2011年1月19日 7:55

回答

  • DaraGridViewのコンボボックス列の中身が、SqlServerから取得したデータをDataSourceで、

    さらにコンボボックスをドロップダウンした時に、各行のデータを「 | 」区切りで整列させて

    一覧表のように表示させる、選択後は、コード値をセルに表示する、ということでしょうか。

    ちょっと作ってみましたので、参考にしてください。

    Public Class Form1
      Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' コンボボックスのデータを作成する
        Dim dtCombo As New DataTable()
        dtCombo.Columns.Add("dtComboValue")
        dtCombo.Columns.Add("dtComboDisplay1")
        dtCombo.Columns.Add("dtComboDisplay2")
        dtCombo.Columns.Add("dtComboDisplay3")
        dtCombo.Rows.Add(0, "コンボ0", "あ", "テストです。")
        dtCombo.Rows.Add(1, "コンボ1", "いい", "テスト")
        dtCombo.Rows.Add(2, "コンボ2", "ううう", "ほげほげ")
        dtCombo.Rows.Add(3, "コンボ3", "ええええ", "ふがふが")
        dtCombo.Rows.Add(4, "コンボ4", "おおおおお", "ぴよぴよ")
        dtCombo.Rows.Add(5, "コンボ5", "かかかかかか", "あいうえお")
        dtCombo.Rows.Add(6, "コンボ6", "ききききき", "一覧表")
        dtCombo.Rows.Add(7, "コンボ7", "くくくく", "拡張ComboBox")
        dtCombo.Rows.Add(8, "コンボ8", "けけけ", "備考")
        dtCombo.Rows.Add(9, "コンボ9", "ここ", "メモメモ")
        ' 一覧表のカラムスタイルを作成
        Dim column1 As New DataGridViewTextBoxColumn()
        column1.Name = "GridColumn1"
        Dim column2 As New DataGridViewComboBoxColumnEx()
        column2.Name = "GridColumn2"
        column2.DataSource = dtCombo
        column2.ValueMember = "dtComboValue"
        Me.DataGridView1.Columns.Add(column1)
        Me.DataGridView1.Columns.Add(column2)
      End Sub
    End Class
    
    ''' <summary>DataGridViewComboBoxColumn拡張コントロール</summary>
    Public Class DataGridViewComboBoxColumnEx
      Inherits DataGridViewComboBoxColumn
      Public Sub New()
        Me.CellTemplate = New DataGridViewComboBoxCellEx
      End Sub
    End Class
    
    ''' <summary>DataGridViewComboBoxCell拡張コントロール</summary>
    Public Class DataGridViewComboBoxCellEx
      Inherits DataGridViewComboBoxCell
      Public Overrides ReadOnly Property EditType() As Type
        Get
          Return GetType(DataGridViewComboBoxEditingControlEx)
        End Get
      End Property
    End Class
    
    ''' <summary>DataGridViewComboBoxEditingControl拡張コントロール</summary>
    Public Class DataGridViewComboBoxEditingControlEx
      Inherits DataGridViewComboBoxEditingControl
    
      ''' <summary>複数列幅</summary>
      Private _ColumnsMesure() As Integer
    
      ''' <summary>コンストラクタ</summary>
      Public Sub New()
        MyBase.New()
        ' 描画モード
        Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawFixed
        ' コンボ ボックスのスタイル
        Me.DropDownStyle = ComboBoxStyle.DropDownList
      End Sub
      ''' <summary>オーナー描画</summary>
      Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
        ' 初期化
        Dim cboColumn As DataGridViewComboBoxColumnEx _
        = Me.EditingControlDataGridView.Columns(Me.EditingControlDataGridView.CurrentCell.ColumnIndex)
        Dim dtCombo As DataTable = cboColumn.DataSource
        If dtCombo Is Nothing Then
          Return
        End If
        ' 拡張コンボボックスコントロール用の列幅を計算
        Array.Resize(Me._ColumnsMesure, dtCombo.Columns.Count)
        For Each row As DataRow In dtCombo.Rows
          For i As Integer = 0 To row.ItemArray.Count - 1
            Dim w As Integer = Me.CreateGraphics.MeasureString(row.Item(i), e.Font).Width
            If Me._ColumnsMesure(i) < w Then
              Me._ColumnsMesure(i) = w
            End If
          Next
        Next
        ' ドロップダウンリストの幅を設定
        Me.Width = (From r In Me._ColumnsMesure Select r).Sum() + SystemInformation.VerticalScrollBarWidth
        ' ドロップダウンアイテムサイズを取得
        Dim rec As New Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height)
        ' ドロップダウンアイテムの背景を描画
        If Me.Enabled Then
          If (e.State And DrawItemState.Focus) = DrawItemState.Focus Then
            ' フォーカス行の背景
            e.Graphics.FillRectangle(New SolidBrush(System.Drawing.SystemColors.Highlight), rec)
          ElseIf (e.State And DrawItemState.ComboBoxEdit) = DrawItemState.ComboBoxEdit OrElse e.Index Mod 2 = 1 Then
            ' 奇数行の背景
            e.Graphics.FillRectangle(New SolidBrush(System.Drawing.SystemColors.Window), rec)
          Else
            ' 偶数行の背景
            e.Graphics.FillRectangle(New SolidBrush(System.Drawing.SystemColors.ControlLight), rec)
          End If
        Else
          ' 無効時の背景
          e.Graphics.FillRectangle(New SolidBrush(System.Drawing.SystemColors.Control), rec)
        End If
        ' ドロップダウンアイテムを描画
        If e.Index > -1 Then
          Dim obj As Object = Me.Items(e.Index)
          Dim rv As DataRowView = CType(obj, DataRowView)
          Dim recColumn As Rectangle
          Dim strItemValue As String
          Dim colLeft As Integer
          For i = 0 To rv.Row.ItemArray.Count - 1
            colLeft = (From r In Me._ColumnsMesure Select r).Take(i).Sum()
            If Me._ColumnsMesure(i) <> 0 Then
              ' アイテムサイズを取得
              recColumn = New Rectangle(colLeft, e.Bounds.Y, Me._ColumnsMesure(i), e.Bounds.Height)
              ' 文字描画
              strItemValue = rv.Row.Item(i).ToString
              If CBool(e.State And DrawItemState.Selected) Then
                ' フォーカス行の背景
                e.Graphics.DrawString( _
                  strItemValue, e.Font, _
                  New SolidBrush(System.Drawing.SystemColors.HighlightText), recColumn)
              Else
                ' それ以外
                e.Graphics.DrawString( _
                  strItemValue, e.Font, _
                  New SolidBrush(System.Drawing.SystemColors.ControlText), recColumn)
              End If
              '境界線描画
              e.Graphics.DrawLine( _
                New Pen(System.Drawing.SystemColors.ControlDark), _
                colLeft, e.Bounds.Top, colLeft, e.Bounds.Bottom)
            End If
          Next
        Else
          Dim NormalText As New SolidBrush(System.Drawing.SystemColors.ControlText)
          e.Graphics.DrawString("", e.Font, NormalText, rec)
        End If
      End Sub
    End Class

    • 回答としてマーク ジョウジ 2011年1月20日 9:58
    2011年1月19日 12:42
  • 返事が遅くなり、申し訳ございません。


    上記コードを参考に解決したいと思います。
    もう少しDataGridViewを勉強し理解してから
    ひき続き質問したいと思います。

    ご回答いただいき、ありがとうございました。
    • 回答としてマーク ジョウジ 2011年1月20日 10:01
    2011年1月20日 10:01

すべての返信

  • SqlServerから取得したデータをDataGridViewのDataSourceに指定し、

    特定のカラムはコンボボックスにしたい、ということですね。

    コンボボックスの中身のデータがどうなっているのかが不明なので、以下はコンボボックス

    のデータもSqlServerから取得する前提で書きます。

     

    基本的な流れとしては、まずはDataGridViewのカラムを設定します。

    カラムを設定するときに、コンボボックス列にしたいカラムのDataSourceには、

    SqlServerから取得したコンボボックスデータを指定します。

    次に、DataGridViewの「AutoGenerateColumns」をFalseに設定し、

    自動的にカラムが作成されないようにします。

    最後に、DataGridViewのDataSourceを設定し、DataGridViewに設定したカラム情報と

    DataSourceに設定したDataTableの列とを関連付けます。

     

    以下、簡単なサンプルです。

    新規プロジェクトのForm1にデザイナでDataGridViewをドラッグドロップで適当に配置し、

    ソースのFormLoadあたりに以下を貼りつけてみてください。

    ちなみに、サンプルではSqlServerから取得するデータは、ダミーを作成してます。

        ' 一覧表のデータを作成する
        Dim dtGrid As New DataTable()
        dtGrid.Columns.Add("dtGridColumn1")
        dtGrid.Columns.Add("dtGridColumn2")
        dtGrid.Rows.Add("1行目", 0)
        dtGrid.Rows.Add("2行目", 1)
        dtGrid.Rows.Add("3行目", 2)
        dtGrid.Rows.Add("4行目", 3)
    
        ' コンボボックスのデータを作成する
        Dim dtCombo As New DataTable()
        dtCombo.Columns.Add("dtComboValue")
        dtCombo.Columns.Add("dtComboDisplay")
        dtCombo.Rows.Add(0, "コンボ0")
        dtCombo.Rows.Add(1, "コンボ1")
        dtCombo.Rows.Add(2, "コンボ2")
        dtCombo.Rows.Add(3, "コンボ3")
    
        ' 一覧表のカラムスタイルを作成
        Dim column1 As New DataGridViewTextBoxColumn()
        column1.Name = "GridColumn1"
        Dim column2 As New DataGridViewComboBoxColumn()
        column2.Name = "GridColumn2"
        column2.DataSource = dtCombo
        column2.DisplayMember = "dtComboDisplay"
        column2.ValueMember = "dtComboValue"
        Me.DataGridView1.Columns.Add(column1)
        Me.DataGridView1.Columns.Add(column2)
    
        ' 一覧表のデータ関連付け
        Me.DataGridView1.AutoGenerateColumns = False
        Me.DataGridView1.DataSource = dtGrid
        Me.DataGridView1.Columns("GridColumn1").DataPropertyName = dtGrid.Columns("dtGridColumn1").ColumnName
        Me.DataGridView1.Columns("GridColumn2").DataPropertyName = dtGrid.Columns("dtGridColumn2").ColumnName
    
    

     

    2011年1月19日 8:55
  • honefaiさん回答ありがとうございます。

    すいません説明が分かりづらくて、

    DataGridViewでDataGridViewComboBoxColumnを使いその中に
    複数列データを表示したいと思っております

    (例)

    00001 | 会田  |アイダ
    00002 | 飯田  |イイダ
    00003 | 大田    |オオタ

    入力はコード番号で、1つ隣のセルには名前を、2つ隣のセルにはカナを
    選択と同時にテキストボックスにセットしたいと考えております。

    Public Class Demo
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            ' 一覧表のデータを作成する
            Dim dtGrid As New DataTable()
            dtGrid.Columns.Add("dtGridColumn1")
            dtGrid.Columns.Add("dtGridColumn2")
            dtGrid.Rows.Add("1行目", 0)
            dtGrid.Rows.Add("2行目", 1)
            dtGrid.Rows.Add("3行目", 2)
            dtGrid.Rows.Add("4行目", 3)

            ' コンボボックスのデータを作成する
            Dim dtCombo As New DataTable()
            dtCombo.Columns.Add("dtComboValue")
            dtCombo.Columns.Add("dtComboDisplay")
            dtCombo.Rows.Add(0, "コンボ0")
            dtCombo.Rows.Add(1, "コンボ1")
            dtCombo.Rows.Add(2, "コンボ2")
            dtCombo.Rows.Add(3, "コンボ3")

            ' 一覧表のカラムスタイルを作成
            Dim column1 As New DataGridViewTextBoxColumn()
            column1.Name = "GridColumn1"
            Dim column2 As New DataGridViewComboBoxColumn()
            column2.Name = "GridColumn2"
            column2.DataSource = dtCombo
            column2.DisplayMember = "dtComboDisplay"
            column2.ValueMember = "dtComboValue"
            Me.DataGridViewDemo.Columns.Add(column1)
            Me.DataGridViewDemo.Columns.Add(column2)

            ' 一覧表のデータ関連付け
            Me.DataGridViewDemo.AutoGenerateColumns = False
            Me.DataGridViewDemo.DataSource = dtGrid
            Me.DataGridViewDemo.Columns("GridColumn1").DataPropertyName = dtGrid.Columns("dtGridColumn1").ColumnName
            Me.DataGridViewDemo.Columns("GridColumn2").DataPropertyName = dtGrid.Columns("dtGridColumn2").ColumnName
        End Sub

        'Public Sub New()

        '    ' This call is required by the Windows Form Designer.
        '    InitializeComponent()

        '    ' Add any initialization after the InitializeComponent() call.
        '    WidgetsDropDownBindingSource.DataSource = New Widgets
        '    WidgetsBindingSource.DataSource = New Widgets
        'End Sub
    End Class

    ダウンロードしたコードで上記のように変更を加えました、

    'Public Sub New()のクラスを全体をコメントしたら

    DropDownListColumn.vbを読みに行かなくなり

    どの様に上記のソースを変更すればOnDrawItemやDropDownListEditingControl

    を見に行くようになりますか?

    すいませんめちゃめちゃな質問で、DataGridViewを今回初めて使います。

    コメント、よろしくお願いします。

    2011年1月19日 9:57
  • DaraGridViewのコンボボックス列の中身が、SqlServerから取得したデータをDataSourceで、

    さらにコンボボックスをドロップダウンした時に、各行のデータを「 | 」区切りで整列させて

    一覧表のように表示させる、選択後は、コード値をセルに表示する、ということでしょうか。

    ちょっと作ってみましたので、参考にしてください。

    Public Class Form1
      Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' コンボボックスのデータを作成する
        Dim dtCombo As New DataTable()
        dtCombo.Columns.Add("dtComboValue")
        dtCombo.Columns.Add("dtComboDisplay1")
        dtCombo.Columns.Add("dtComboDisplay2")
        dtCombo.Columns.Add("dtComboDisplay3")
        dtCombo.Rows.Add(0, "コンボ0", "あ", "テストです。")
        dtCombo.Rows.Add(1, "コンボ1", "いい", "テスト")
        dtCombo.Rows.Add(2, "コンボ2", "ううう", "ほげほげ")
        dtCombo.Rows.Add(3, "コンボ3", "ええええ", "ふがふが")
        dtCombo.Rows.Add(4, "コンボ4", "おおおおお", "ぴよぴよ")
        dtCombo.Rows.Add(5, "コンボ5", "かかかかかか", "あいうえお")
        dtCombo.Rows.Add(6, "コンボ6", "ききききき", "一覧表")
        dtCombo.Rows.Add(7, "コンボ7", "くくくく", "拡張ComboBox")
        dtCombo.Rows.Add(8, "コンボ8", "けけけ", "備考")
        dtCombo.Rows.Add(9, "コンボ9", "ここ", "メモメモ")
        ' 一覧表のカラムスタイルを作成
        Dim column1 As New DataGridViewTextBoxColumn()
        column1.Name = "GridColumn1"
        Dim column2 As New DataGridViewComboBoxColumnEx()
        column2.Name = "GridColumn2"
        column2.DataSource = dtCombo
        column2.ValueMember = "dtComboValue"
        Me.DataGridView1.Columns.Add(column1)
        Me.DataGridView1.Columns.Add(column2)
      End Sub
    End Class
    
    ''' <summary>DataGridViewComboBoxColumn拡張コントロール</summary>
    Public Class DataGridViewComboBoxColumnEx
      Inherits DataGridViewComboBoxColumn
      Public Sub New()
        Me.CellTemplate = New DataGridViewComboBoxCellEx
      End Sub
    End Class
    
    ''' <summary>DataGridViewComboBoxCell拡張コントロール</summary>
    Public Class DataGridViewComboBoxCellEx
      Inherits DataGridViewComboBoxCell
      Public Overrides ReadOnly Property EditType() As Type
        Get
          Return GetType(DataGridViewComboBoxEditingControlEx)
        End Get
      End Property
    End Class
    
    ''' <summary>DataGridViewComboBoxEditingControl拡張コントロール</summary>
    Public Class DataGridViewComboBoxEditingControlEx
      Inherits DataGridViewComboBoxEditingControl
    
      ''' <summary>複数列幅</summary>
      Private _ColumnsMesure() As Integer
    
      ''' <summary>コンストラクタ</summary>
      Public Sub New()
        MyBase.New()
        ' 描画モード
        Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawFixed
        ' コンボ ボックスのスタイル
        Me.DropDownStyle = ComboBoxStyle.DropDownList
      End Sub
      ''' <summary>オーナー描画</summary>
      Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
        ' 初期化
        Dim cboColumn As DataGridViewComboBoxColumnEx _
        = Me.EditingControlDataGridView.Columns(Me.EditingControlDataGridView.CurrentCell.ColumnIndex)
        Dim dtCombo As DataTable = cboColumn.DataSource
        If dtCombo Is Nothing Then
          Return
        End If
        ' 拡張コンボボックスコントロール用の列幅を計算
        Array.Resize(Me._ColumnsMesure, dtCombo.Columns.Count)
        For Each row As DataRow In dtCombo.Rows
          For i As Integer = 0 To row.ItemArray.Count - 1
            Dim w As Integer = Me.CreateGraphics.MeasureString(row.Item(i), e.Font).Width
            If Me._ColumnsMesure(i) < w Then
              Me._ColumnsMesure(i) = w
            End If
          Next
        Next
        ' ドロップダウンリストの幅を設定
        Me.Width = (From r In Me._ColumnsMesure Select r).Sum() + SystemInformation.VerticalScrollBarWidth
        ' ドロップダウンアイテムサイズを取得
        Dim rec As New Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height)
        ' ドロップダウンアイテムの背景を描画
        If Me.Enabled Then
          If (e.State And DrawItemState.Focus) = DrawItemState.Focus Then
            ' フォーカス行の背景
            e.Graphics.FillRectangle(New SolidBrush(System.Drawing.SystemColors.Highlight), rec)
          ElseIf (e.State And DrawItemState.ComboBoxEdit) = DrawItemState.ComboBoxEdit OrElse e.Index Mod 2 = 1 Then
            ' 奇数行の背景
            e.Graphics.FillRectangle(New SolidBrush(System.Drawing.SystemColors.Window), rec)
          Else
            ' 偶数行の背景
            e.Graphics.FillRectangle(New SolidBrush(System.Drawing.SystemColors.ControlLight), rec)
          End If
        Else
          ' 無効時の背景
          e.Graphics.FillRectangle(New SolidBrush(System.Drawing.SystemColors.Control), rec)
        End If
        ' ドロップダウンアイテムを描画
        If e.Index > -1 Then
          Dim obj As Object = Me.Items(e.Index)
          Dim rv As DataRowView = CType(obj, DataRowView)
          Dim recColumn As Rectangle
          Dim strItemValue As String
          Dim colLeft As Integer
          For i = 0 To rv.Row.ItemArray.Count - 1
            colLeft = (From r In Me._ColumnsMesure Select r).Take(i).Sum()
            If Me._ColumnsMesure(i) <> 0 Then
              ' アイテムサイズを取得
              recColumn = New Rectangle(colLeft, e.Bounds.Y, Me._ColumnsMesure(i), e.Bounds.Height)
              ' 文字描画
              strItemValue = rv.Row.Item(i).ToString
              If CBool(e.State And DrawItemState.Selected) Then
                ' フォーカス行の背景
                e.Graphics.DrawString( _
                  strItemValue, e.Font, _
                  New SolidBrush(System.Drawing.SystemColors.HighlightText), recColumn)
              Else
                ' それ以外
                e.Graphics.DrawString( _
                  strItemValue, e.Font, _
                  New SolidBrush(System.Drawing.SystemColors.ControlText), recColumn)
              End If
              '境界線描画
              e.Graphics.DrawLine( _
                New Pen(System.Drawing.SystemColors.ControlDark), _
                colLeft, e.Bounds.Top, colLeft, e.Bounds.Bottom)
            End If
          Next
        Else
          Dim NormalText As New SolidBrush(System.Drawing.SystemColors.ControlText)
          e.Graphics.DrawString("", e.Font, NormalText, rec)
        End If
      End Sub
    End Class

    • 回答としてマーク ジョウジ 2011年1月20日 9:58
    2011年1月19日 12:42
  • 返事が遅くなり、申し訳ございません。


    上記コードを参考に解決したいと思います。
    もう少しDataGridViewを勉強し理解してから
    ひき続き質問したいと思います。

    ご回答いただいき、ありがとうございました。
    • 回答としてマーク ジョウジ 2011年1月20日 10:01
    2011年1月20日 10:01