トップ回答者
DataGridViewでの複数列ComboBox(Access風)

質問
-
ジョウジと申します、初めての投稿です。
VB2008とSQL2008を使用し開発しております、
DataGridViewで複数列表示のAccess風のコンボボックスを
実現したいと思います、色々ネットで調べたところ…
下記リンクのホームページで問題内容に近い例を見つけました。
http://www.codeproject.com/KB/cpp/DropDownListColumn.aspx
ダウンロードし実行しましたが、経験があさいせいか、なかなか解決できません。
上記サイトのソースコードを修正し実現できればと思っています。
もしくは初心者でも分かりやすいサイトなど、いろいろな情報お待ちしております、
ご教授宜しくお願います。
回答
-
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
すべての返信
-
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
-
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を今回初めて使います。
コメント、よろしくお願いします。
-
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