tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板)
VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板)
[ツリー表示へ]  [ワード検索]  [Home]

タイトル Re^5: DataGridViewのComboBoxColumnのコレクションを単一選択にしたい
投稿日: 2007/05/15(Tue) 13:08
投稿者魔界の仮面弁士
となると、CellValueChanged イベントが妥当でしょう。
e.ColumnIndex と e.RowIndex から、選択された値を取得して、
その値が他の行で既に使われていたら、その行の値をクリアする、と。

たとえば、こんな感じ。
--------------
Public Class Form1

  '実験用のダミーデータ生成。このあたりは適当に。
  Private Function CreateComboItem() As String()
    Dim list As New List(Of String)
    list.Add("")
    list.Add("Visual Basic")
    list.Add("C#")
    list.Add("C++/CLI")
    list.Add("JScript")
    list.Add("Delphi")
    Return list.ToArray()
  End Function

  '説明の都合上、今回はコントロール生成も Form1_Load で行っていますが、
  '普通は、デザイン時に設定しておくだけで十分です。
  Private WithEvents dataGridView1 As New DataGridView()
  Private comboColumn1 As DataGridViewComboBoxColumn
  Private items() As String

  Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs _
  ) Handles MyBase.Load
    'コンボボックス列の設定
    comboColumn1 = New DataGridViewComboBoxColumn()
    comboColumn1.DataSource = CreateComboItem()

    'グリッドの設定
    dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter
    dataGridView1.Dock = DockStyle.Fill
    dataGridView1.ColumnHeadersVisible = False
    dataGridView1.RowHeadersVisible = False
    dataGridView1.AllowUserToResizeRows = False
    dataGridView1.AllowUserToResizeColumns = False
    dataGridView1.AllowUserToAddRows = False
    dataGridView1.DefaultCellStyle.SelectionBackColor = _
             dataGridView1.DefaultCellStyle.BackColor
    dataGridView1.DefaultCellStyle.SelectionForeColor = _
             dataGridView1.DefaultCellStyle.ForeColor
    dataGridView1.RowCount = 5
    dataGridView1.ColumnCount = 1
    dataGridView1.Columns.Add(comboColumn1)
    Controls.Add(dataGridView1)

    'おまけ
    Dim combo As New DataGridViewComboBoxCell()
    combo.Items.AddRange("犬 猿 雉".Split())
    dataGridView1(0, 0) = combo
    dataGridView1(0, 0).Value = "猿"
    dataGridView1(0, 1).Style.BackColor = Color.Gold
    dataGridView1(0, 1).Style.ForeColor = Color.Red
    dataGridView1(0, 1).Value = "テキスト"
    dataGridView1(0, 2) = New DataGridViewButtonCell()
    dataGridView1(0, 2).Value = "ボタン"
    dataGridView1(0, 3) = New DataGridViewImageCell(False)
    dataGridView1(0, 3).Value = Me.Icon
    dataGridView1(0, 4) = New DataGridViewCheckBoxCell()
    dataGridView1(0, 4).Style.Alignment = DataGridViewContentAlignment.MiddleCenter
    dataGridView1(0, 4).Value = True
  End Sub

  'ここから本題。
  Private Sub dataGridView1_CellValueChanged(ByVal sender As Object, _
  ByVal e As DataGridViewCellEventArgs) Handles dataGridView1.CellValueChanged
    If e.ColumnIndex <> comboColumn1.Index Then
      Return
    End If

    '選択されたコンボ項目を取得
    Dim dgv As DataGridView = DirectCast(sender, DataGridView)
    Dim value As String = dgv(e.ColumnIndex, e.RowIndex).Value.ToString()

    If value = "" Then
      '未選択状態の時は、特に何もしない
      Return
    End If

    '他の行の状態を確認
    For rowIndex As Integer = 0 To dgv.RowCount - 1
      If rowIndex = e.RowIndex Then
        '自分は除外
        Continue For
      End If
      Dim cell As DataGridViewCell = dgv(e.ColumnIndex, rowIndex)
      If Object.Equals(cell.Value, value) Then
        '同じ値を持つ行があれば、未選択に戻す
        cell.Value = ""
        Exit For
      End If
    Next
  End Sub
End Class
----------

この場合、重複した他のセルの値がクリアされるのは、コンボボックスから
選択したときではなく、選択後にそのセルからフォーカスが抜けたときです。

もしセルを移動させることなく、項目が選択されるたびに、即座に他の行の値を
クリアしたいのであれば、CurrentCellDirtyStateChanged イベントでコミットすれば OK です。

Private Sub dataGridView1_CurrentCellDirtyStateChanged(……
  If dataGridView1.CurrentCell.ColumnIndex = comboColumn1.Index Then
    dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
  End If
End Sub

ただ、即座にコミットすると見た目はわかりやすいのですが、それだと困ることもあります。
ドロップダウンからのクリックで選択した場合であれば良いのですが、マウスホイールや
矢印キーで選択した場合には、そのたびに他の行の値が次々とクリアされる結果になるので。

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。