【问题标题】:How do you assign different data sources for a DataGridViewComboBox for each record?如何为每条记录的 DataGridViewComboBox 分配不同的数据源?
【发布时间】:2015-07-01 04:22:32
【问题描述】:

我有一个 winforms DataGridView,我希望有一个包含每条记录的组合框的列。每个组合框的每一行都将具有完全不同的值,并且需要在 DataGridView 的数据绑定期间分配一个数据源。我可以为所有数据源分配 1 个数据源(这很容易),但是让每个组合框都有不同的值看起来是不可能的)。

这是我正在使用的 - 注意:DataGridView 的数据源是通过设置调用表单的属性以编程方式定义的。

Public Class frmSendToQuickbooksPopup

    Public Property CurrentOrder As OrderICT
    Public Property lineitems As List(Of OrderLineItemICT)

    Private Sub frmSendToQuickbooksPopup_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        'define the combobox (datasource can't be assigned here as each will be different for each row)
        Dim dgvcboMatch As New DataGridViewComboBoxColumn
        dgvcboMatch.DisplayMember = "Name"
        dgvcboMatch.ValueMember = "ListID"
        dgvcboMatch.HeaderText = "Matches"
        dgvcboMatch.Name = "Match"
        dgvcboMatch.Width = 150
        dgvLineItems.Columns.Add(dgvcboMatch)

        Me.dgvLineItems.DataSource = lineitems
    End Sub

    Private Sub dgvLineItems_DataSourceChanged(sender As Object, e As EventArgs) Handles dgvLineItems.DataSourceChanged
        Dim L As New QBI.OrderLineItemICT
        With L
            dgvLineItems.Columns(.col_LineItemBvin).Visible = False
            dgvLineItems.Columns(.col_ProductId).Visible = False
            dgvLineItems.Columns(.col_ProductShortDescription).Visible = False
            dgvLineItems.Columns(.col_ShippingBoxCount).Visible = False
            dgvLineItems.Columns(.col_CustomProperties).Visible = False
            dgvLineItems.Columns(.col_ShippingLength).Visible = False
            dgvLineItems.Columns(.col_ShippingWidth).Visible = False
            dgvLineItems.Columns(.col_ShippingHeight).Visible = False
            dgvLineItems.Columns(.col_ProductName).DisplayIndex = 2
            dgvLineItems.Columns(.col_ProductName).HeaderText = "Product Name"
            dgvLineItems.Columns(.col_ProductName).Width = 170
            dgvLineItems.Columns(.col_ProductSku).HeaderText = "SKU"
            dgvLineItems.Columns(.col_ProductSku).Width = 160
            dgvLineItems.Columns(.col_Quantity).DefaultCellStyle.Format = "n0"
            dgvLineItems.Columns(.col_Quantity).DisplayIndex = 7
            dgvLineItems.Columns(.col_Quantity).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
            dgvLineItems.Columns(.col_Quantity).Width = 65
            dgvLineItems.Columns(.col_AdjustedPrice).DefaultCellStyle.Format = "c2"
            dgvLineItems.Columns(.col_AdjustedPrice).HeaderText = "Adj Price"
            dgvLineItems.Columns(.col_AdjustedPrice).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            dgvLineItems.Columns(.col_AdjustedPrice).Width = 80
            dgvLineItems.Columns(.col_BasePrice).DefaultCellStyle.Format = "c2"
            dgvLineItems.Columns(.col_BasePrice).HeaderText = "Base Price"
            dgvLineItems.Columns(.col_BasePrice).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            dgvLineItems.Columns(.col_BasePrice).Width = 85
            dgvLineItems.Columns(.col_Discounts).DefaultCellStyle.Format = "c2"
            dgvLineItems.Columns(.col_Discounts).HeaderText = "Discounts"
            dgvLineItems.Columns(.col_Discounts).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            dgvLineItems.Columns(.col_Discounts).Width = 80
            dgvLineItems.Columns(.col_LineTotal).DefaultCellStyle.Format = "c2"
            dgvLineItems.Columns(.col_LineTotal).HeaderText = "Line Total"
            dgvLineItems.Columns(.col_LineTotal).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            dgvLineItems.Columns(.col_LineTotal).Width = 80
            dgvLineItems.Columns(.col_UOM).DisplayIndex = 9
            dgvLineItems.Columns(.col_UOM).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
            dgvLineItems.Columns(.col_UOM).HeaderText = "Units"
            dgvLineItems.Columns(.col_UOM).Width = 55
            dgvLineItems.Columns(.col_ShippingWeight).DisplayIndex = 10
            dgvLineItems.Columns(.col_ShippingWeight).HeaderText = "Unit Wt"
            dgvLineItems.Columns(.col_ShippingWeight).DefaultCellStyle.Format = "N1"
            dgvLineItems.Columns(.col_ShippingWeight).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            dgvLineItems.Columns(.col_ShippingWeight).Width = 70
        End With
    End Sub

Public Function GetComboboxData(ProductNameToMatch As String, ProductSKUToMatch As String) As List(Of WPM_Item)
    'this function returns a list of returned matches for a given row's ProductName or SKU
    'this function will be the datasource for a given combobox
    Dim itms As New List(Of WPM_Item)
    itms = WPM_Data.FindWPM_ItemMatch(ProductNameToMatch, ProductSKUToMatch)
    Return itms
End Function



End Class

如果有某种方法可以拦截 DataGridView 的数据绑定,以便我可以从另一个单元格获取值(以调用另一个过程),然后使用返回数据填充每一行的组合框。这很容易使用 webforms,但我没有看到 winforms 版本的事件。


我尝试过的另一件事,但不起作用(组合框数据源消失了!)

Private Sub dgvLineItems_DataBindingComplete(sender As Object, e As DataGridViewBindingCompleteEventArgs) Handles dgvLineItems.DataBindingComplete
    For Each row As DataGridViewRow In Me.dgvLineItems.Rows
        Dim dr = DirectCast(row.DataBoundItem, OrderLineItemICT)
        If dr Is Nothing Then
            Return
        End If

        Dim name As String = row.Cells(dr.col_ProductName).Value.ToString
        Dim SKU As String = row.Cells(dr.col_ProductSku).Value.ToString

        Dim cell As DataGridViewComboBoxCell = TryCast(row.Cells("Match"), DataGridViewComboBoxCell)
        cell.DisplayStyle = DataGridViewComboBoxDisplayStyle.ComboBox

        Dim wpm_items As List(Of WPM_Item) = GetComboboxData(name, SKU)
        If cell.DataSource Is Nothing Then
            cell.DataSource = wpm_items 'this forgets the datasource, why?
            cell.DisplayMember = "Name"
            cell.ValueMember = "ListID"
            cell.Value = wpm_items.Item(0).Name 'this always throws an error "DataGridViewComboBoxCell value is not valid."
        End If

    Next

End Sub

这是同一分配的另一个版本,这次组合框填充了 add 方法。 (仍然不记得这些值) 我基本上遵循了另一个论坛的想法 - 也许 DotNet 4.5 DataGridView 有一个错误。

Private Sub dgvLineItems_DataBindingComplete(sender As Object, e As DataGridViewBindingCompleteEventArgs) Handles dgvLineItems.DataBindingComplete
    For Each row As DataGridViewRow In Me.dgvLineItems.Rows
        Dim dr = DirectCast(row.DataBoundItem, OrderLineItemICT)
        If dr Is Nothing Then
            Return
        End If

        Dim name As String = row.Cells(dr.col_ProductName).Value.ToString
        Dim SKU As String = row.Cells(dr.col_ProductSku).Value.ToString

        Dim cell As DataGridViewComboBoxCell = DirectCast(row.Cells("Match"), DataGridViewComboBoxCell)
        cell.DisplayStyle = DataGridViewComboBoxDisplayStyle.ComboBox

        Dim wpm_items As List(Of WPM_Item) = GetComboboxData(name, SKU)

        'THIS DOES NOT WORK EITHER!! 
        cell.DisplayMember = "Name"
        cell.ValueMember = "ListID"
        For Each wItm As WPM_Item In wpm_items
            Dim c As New comboboxitem
            c.Text = wItm.Name
            c.Value = wItm.ListID
            cell.Items.Add(c)
        Next
    Next
End Sub
Public Class ComboboxItem
    Public Property Text() As String
    Public Property Value() As Object

    Public Overrides Function ToString() As String
        Return Text
    End Function
End Class

【问题讨论】:

    标签: vb.net winforms datagridview combobox


    【解决方案1】:

    那好吧!这是一个有效的解决方案。我发现您必须以编程方式创建 DataGridView(乏味,是的!)并关闭列的自动生成(绝对必须) - 这可以防止多次触发 dataGridView 事件。它还可以防止丢失组合框的数据源。使用 DataBindingComplete 事件并解析其中的行是最好的方法(CellFormatting 事件是多余的,每次鼠标移动、单击、调整大小等都会调用它)。 对于我们这些使用对象而不是数据表的人,我希望这个解决方案是可用的。

    代码:

    Imports QBI
    Imports QBI.QBI
    Imports QBI.AppCore.Xutilities
    
    Public Class TestDGV1
    
        Public dgv1 As DataGridView
    
        Private Sub TestDGV1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            Dim ordlineitems As List(Of OrderLineItemICT)
            ordlineitems = Order_DataICT.GetNewOrderLineItemsICT("26073bff-3a08-4bc2-8da9-79c75534bd6b")
            dgv1 = Me.CreateDGV(ordlineitems) 'create the DataGridView and save it as "dgv1" (which must be publically accessible)
    
            Me.SplitContainer1.Panel2.Controls.Add(dgv1) 'NOTE, the datagridview is inside a SplitContainer
        End Sub
    
        Public Function CreateDGV(dsItems As List(Of OrderLineItemICT)) As DataGridView
            Dim dgv As New DataGridView()
            dgv.Dock = DockStyle.Fill
            dgv.DataSource = dsItems
            dgv.EditMode = DataGridViewEditMode.EditOnEnter
            dgv.AutoGenerateColumns = False
            dgv.AllowUserToAddRows = False
    
            Dim L As New QBI.OrderLineItemICT 'only using this reference for my column names defined elsewhere
    
            Dim col0 As New DataGridViewComboBoxColumn With {.Name = "Match", .DataPropertyName = "NameMatch", .DisplayMember = "Name", .ValueMember = "ListID", .HeaderText = "Matches", .AutoComplete = True}
            col0.DisplayIndex = 0
    
            Dim col1 As New DataGridViewTextBoxColumn With {.Name = L.col_LineItemBvin, .DataPropertyName = L.col_LineItemBvin, .Visible = False, .ReadOnly = True, .HeaderText = L.col_LineItemBvin}
            col1.DisplayIndex = 1
    
            Dim col2 As New DataGridViewTextBoxColumn With {.Name = L.col_ProductId, .DataPropertyName = L.col_ProductId, .Visible = False, .ReadOnly = True, .HeaderText = L.col_ProductId}
            col2.DisplayIndex = 2
    
            Dim col3 As New DataGridViewTextBoxColumn With {.Name = L.col_ProductSku, .DataPropertyName = L.col_ProductSku, .Visible = True, .ReadOnly = True, .HeaderText = "SKU"}
            col3.DisplayIndex = 3
            col3.Width = 160
            Dim col4 As New DataGridViewTextBoxColumn With {.Name = L.col_Quantity, .DataPropertyName = L.col_Quantity, .Visible = True, .ReadOnly = True, .HeaderText = "QTY"}
            col4.DisplayIndex = 9
            col4.Width = 65
            col4.DefaultCellStyle.Format = "n0"
            col4.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
    
            Dim col5 As New DataGridViewTextBoxColumn With {.Name = L.col_BasePrice, .DataPropertyName = L.col_BasePrice, .Visible = True, .ReadOnly = True, .HeaderText = "Base Price"}
            col5.DisplayIndex = 6
            col5.DefaultCellStyle.Format = "c2"
            col5.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            col5.Width = 85
    
            Dim col6 As New DataGridViewTextBoxColumn With {.Name = L.col_Discounts, .DataPropertyName = L.col_Discounts, .Visible = True, .ReadOnly = True, .HeaderText = "Discounts"}
            col6.DisplayIndex = 7
            col6.DefaultCellStyle.Format = "c2"
            col6.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            col6.Width = 80
    
            Dim col7 As New DataGridViewTextBoxColumn With {.Name = L.col_AdjustedPrice, .DataPropertyName = L.col_AdjustedPrice, .Visible = True, .ReadOnly = True, .HeaderText = "Adj Price"}
            col7.DisplayIndex = 8
            col7.DefaultCellStyle.Format = "c2"
            col7.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            col7.Width = 80
    
            Dim col8 As New DataGridViewTextBoxColumn With {.Name = L.col_LineTotal, .DataPropertyName = L.col_LineTotal, .Visible = True, .ReadOnly = True, .HeaderText = "Line Total"}
            col8.DisplayIndex = 11
            col8.DefaultCellStyle.Format = "c2"
            col8.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            col8.Width = 80
    
            Dim col9 As New DataGridViewTextBoxColumn With {.Name = L.col_ProductName, .DataPropertyName = L.col_ProductName, .Visible = True, .ReadOnly = True, .HeaderText = "Product Name"}
            col9.DisplayIndex = 4
            col9.Width = 170
    
            Dim col10 As New DataGridViewTextBoxColumn With {.Name = L.col_ProductShortDescription, .DataPropertyName = L.col_ProductShortDescription, .Visible = False, .ReadOnly = True, .HeaderText = L.col_ProductShortDescription}
            col10.DisplayIndex = 5
    
            Dim col11 As New DataGridViewTextBoxColumn With {.Name = L.col_ShippingWeight, .DataPropertyName = L.col_ShippingWeight, .Visible = True, .ReadOnly = True, .HeaderText = "Unit Wt"}
            col11.DisplayIndex = 12
            col11.DefaultCellStyle.Format = "N1"
            col11.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            col11.Width = 70
            Dim col12 As New DataGridViewTextBoxColumn With {.Name = L.col_ShippingWidth, .DataPropertyName = L.col_ShippingWidth, .Visible = False, .ReadOnly = True, .HeaderText = L.col_ShippingWidth}
            col12.DisplayIndex = 13
    
            Dim col13 As New DataGridViewTextBoxColumn With {.Name = L.col_ShippingHeight, .DataPropertyName = L.col_ShippingHeight, .Visible = False, .ReadOnly = True, .HeaderText = L.col_ShippingHeight}
            col13.DisplayIndex = 14
    
            Dim col14 As New DataGridViewTextBoxColumn With {.Name = L.col_ShippingBoxCount, .DataPropertyName = L.col_ShippingBoxCount, .Visible = False, .ReadOnly = True, .HeaderText = L.col_ShippingBoxCount}
            col14.DisplayIndex = 15
    
            Dim col15 As New DataGridViewTextBoxColumn With {.Name = L.col_CustomProperties, .DataPropertyName = L.col_CustomProperties, .Visible = False, .ReadOnly = True, .HeaderText = L.col_CustomProperties}
            col15.DisplayIndex = 16
    
            Dim col16 As New DataGridViewTextBoxColumn With {.Name = L.col_UOM, .DataPropertyName = L.col_UOM, .Visible = True, .ReadOnly = True, .HeaderText = "Units"}
            col16.DisplayIndex = 10
            col16.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
            col16.Width = 55
    
            dgv.Columns.AddRange({col0, col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, col11, col12, col13, col14, col15, col16})
    
            AddHandler dgv.DataBindingComplete, AddressOf dgvLineItems_DataBindingComplete
    
            Return dgv
        End Function
    
        Private Sub dgvLineItems_DataBindingComplete(sender As Object, e As DataGridViewBindingCompleteEventArgs)
            For Each row As DataGridViewRow In Me.dgv1.Rows
                Dim dr = DirectCast(row.DataBoundItem, OrderLineItemICT)
                If dr Is Nothing Then
                    Return
                End If
    
                Dim name As String = row.Cells(dr.col_ProductName).Value.ToString
                Dim SKU As String = row.Cells(dr.col_ProductSku).Value.ToString
                Dim cell As DataGridViewComboBoxCell = DirectCast(row.Cells("Match"), DataGridViewComboBoxCell)
                Dim wpm_items As List(Of WPM_Item) = GetComboboxData(name, SKU) 'function inside
                If cell.DataSource Is Nothing Then
                    cell.DataSource = wpm_items 
                    cell.DisplayMember = "Name"
                    cell.ValueMember = "ListID"
                    cell.Value = cell.Items(0).ListID
                End If
            Next
        End Sub
    
        Public Function GetComboboxData(ProductNameToMatch As String, ProductSKUToMatch As String) As List(Of WPM_Item)
            'this function returns a list of returned matches for a given row's ProductName or SKU
            'this function will be the datasource for a given combobox
            Dim itms As New List(Of WPM_Item)
            itms = WPM_Data.FindWPM_ItemMatch(ProductNameToMatch, ProductSKUToMatch)
            Return itms
        End Function
    
    End Class
    

    【讨论】:

      【解决方案2】:

      这是 C# 中的一个示例,说明如何在 DataGridView 中使用不同的 Types 中的 DataGridViewComboBoxColumn

      public static class ComboColumnDemo {
      
          public static DataGridView CreateSampleDGV() {
      
              DataTable table = new DataTable();
              table.Columns.Add("VariableType", typeof(String));
              table.Columns.Add("VariableId", typeof(int));
              table.Columns.Add("Custom", typeof(Object));
              table.Columns.Add("Default", typeof(Object));
              table.Columns.Add("Date", typeof(DateTime));
              table.Rows.Add(new Object[] { "int", 0, null, null, DateTime.MinValue });
              table.Rows.Add(new Object[] { "decimal", 0, null, null, DateTime.MinValue });
              table.Rows.Add(new Object[] { "enum", 0, null, null, DateTime.Now });
              table.Rows.Add(new Object[] { "date", 0, null, null, DateTime.UtcNow });
              table.Rows.Add(new Object[] { "person", 0, null, null, DateTime.Today });
              table.Rows.Add(new Object[] { "String", 0, null, null, DateTime.MaxValue });
      
              DataGridView dgv = new DataGridView();
              dgv.Dock = DockStyle.Fill;
              dgv.DataSource = table;
              dgv.EditMode = DataGridViewEditMode.EditOnEnter;
              dgv.AutoGenerateColumns = false;
              dgv.AllowUserToAddRows = false;
      
              DataGridViewComboBoxColumn colComboDefault = new DataGridViewComboBoxColumn { DataPropertyName = "Default", MaxDropDownItems = 20 };
              //col2.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; //.DropDownButton;
              colComboDefault.AutoComplete = true;
              colComboDefault.ValueType = typeof(Object);
      
              dgv.Columns.Add(new DataGridViewTextBoxColumn() { DataPropertyName = "VariableType" });
              dgv.Columns.Add(new DataGridViewTextBoxColumn() { DataPropertyName = "VariableId" });
              dgv.Columns.Add(colComboDefault);
              dgv.Columns.Add(new CalendarColumn { DataPropertyName = "Date" });
      
              foreach (DataGridViewColumn c in dgv.Columns)
                  c.HeaderText = c.DataPropertyName;
      
              List<Object> strings = new List<Object>(new [] { "a", "b", "c" });
              var ints = new List<Object>(new Object[] { DBNull.Value, 1, 2, 3 });
              var decimals = new List<Object>(new Object[] { 1111111m, 2222222m, 3333333m });
              List<Object> dates = new List<Object>(new Object[] { DBNull.Value, DateTime.Today });
              List<Object> enums = new List<object>();
              enums.Add(DBNull.Value);
              enums.AddRange(Enum.GetValues(typeof(DayOfWeek)).Cast<Object>().ToArray());
      
              DataTable enumsTable = Opulos.Core.Utils.EnumUtil<DayOfWeek>.ToDataTable();
      
              List<Person> persons = new List<Person>();
      
              dgv.CellFormatting += (sender, e) => {
                  var drv = (DataRowView) dgv.Rows[e.RowIndex].DataBoundItem;
                  if (drv == null)
                      return;
      
                  DataRow dr = drv.Row;
                  //String colName = dgv.Columns[col2].DataPropertyName;
      
                  String vt = (String) dr["VariableType"]; //table.Rows[row][0].ToString();
                  if (vt == "decimal" && e.ColumnIndex == 2) {
                      if (e.Value is decimal) {
                          e.Value = ((decimal) e.Value).ToString("n0");
                          e.FormattingApplied = true;
                      }
                  }
              };
      
              dgv.CellBeginEdit += (sender, e) => {
              //dgv.EditingControlShowing += delegate {
                  int rowIndex = e.RowIndex;//dgv.CurrentCell.RowIndex;
                  int colIndex = e.ColumnIndex; //dgv.CurrentCell.ColumnIndex;
                  DataGridViewColumn col = dgv.Columns[colIndex];
      
                  try {
                      var drv = (DataRowView) dgv.Rows[rowIndex].DataBoundItem;
                      if (drv == null)
                          return;
      
                      DataRow dr = drv.Row;
                      //String colName = dgv.Columns[col2].DataPropertyName;
      
                      String vt = (String) dr["VariableType"]; //table.Rows[row][0].ToString();
                      //String vt = vm.VariableType;
      
                      Object items = null;
                      ComboBoxStyle? style = null;
                      Type valueType = null;
                      String formatString = null;
                      String displayMember = null;
                      String valueMember = null;
      
                      if (vt == "String") {
                          items = strings;
                          valueType = typeof(String);
                      }
                      else if (vt == "int") {
                          items = ints;
                          valueType = typeof(int);
                      }
                      else if (vt == "decimal") {
                          items = decimals;
                          formatString = "n0";
                          valueType = typeof(decimal);
                      }
                      else if (vt == "date") {
                          items = dates;
                          valueType = typeof(DateTime);
                      }
                      else if (vt == "enum") {
                          if (col == colComboDefault) {
                              items = enumsTable;
                              displayMember = "Display";
                              valueMember = "Value";
                          }
                          else
                              items = enums;
                          style = ComboBoxStyle.DropDownList;
                          valueType = typeof(DayOfWeek);
                      }
                      else if (vt == "person") {
                          items = persons;
                          valueType = typeof(Person);
                      }
      
                      if (col == colComboDefault) {
                          var cell2 = (DataGridViewComboBoxCell) dgv.Rows[rowIndex].Cells[colIndex];
                          cell2.DataSource = items;
                          cell2.ValueType = valueType;
                          cell2.DisplayMember = displayMember;
                          cell2.ValueMember = valueMember;
                      }
      
                  } catch (Exception ex) {
                      MessageBox.Show(dgv.FindForm(), ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                  }
              };
      
              return dgv;
          }
      }
      
      internal class Person {
          public String name;
          public override string ToString() {
              return name;
          }
      
          public override bool Equals(object obj) {
              if (obj is Person)
                  return String.Compare(name, ((Person) obj).name, false) == 0;
              return false;
          }
      
          public override int GetHashCode() {
              return name.GetHashCode();
          }
      }
      

      【讨论】:

      • 该示例的问题是它仅在编辑单元格时有效。绘制网格时必须填充组合。
      • 好的 - 看起来事件拦截不起作用(CellFormatting 不适合这个目的,因为它几乎一直被触发)。它必须是完全手动创建网格并填写值。我正在试验。
      • 事件拦截是什么意思?以我的经验,最困难的部分是让DataGridView 停止通过混合值引发异常。 CellFormatting 是可选的,但它是格式化数据的正确方法。这是为了说明目的。
      • 事件并不重要。除了在编辑模式下之外,无论如何都不能引用单元格中的控件,只能引用值。换句话说,在绘制时不可能为网格中的每个组合框分配不同的数据源。
      • 我认为我可以解决这个问题的方法是为所有不同的组合框创建所有数据源,然后像您的示例一样在代码中创建 datagridview。
      【解决方案3】:

      解决方案

      使用DataBindingComplete 事件处理程序遍历您的行并为每个DataGridViewComboBoxCell 设置源。

      示例

      这是我如何做到这一点的一个例子。您需要将DataGridViewComboBox(有两个选项,即“选项1”和“选项2”,用于切换DataGridView.DataSource)添加到Form

      Public Class Form1
      
          Public Property Groups As List(Of Group)
      
          Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
      
              Me.Groups = Me.InitializeGroups()
      
              Dim cbc As New DataGridViewComboBoxColumn()
              cbc.DisplayMember = "Name"
              cbc.ValueMember = "ID"
              cbc.HeaderText = "Matches"
              cbc.Name = "Match"
              cbc.Width = 150
              Me.DataGridView1.Columns.Add(cbc)
      
              Me.ComboBox1.SelectedIndex = 0
          End Sub
      
          Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
              Dim examples As New List(Of Example)()
      
              If Me.ComboBox1.SelectedIndex = 0 Then
                  examples.Add(New Example("Me", "blah"))
                  examples.Add(New Example("You", "blah"))
              Else
                  examples.Add(New Example("Him", "blah"))
                  examples.Add(New Example("Her", "blah"))
                  examples.Add(New Example("It", "blah"))
              End If
      
              Me.DataGridView1.DataSource = examples
          End Sub
      
          Private Sub DataGridView1_DataBindingComplete(sender As Object, e As DataGridViewBindingCompleteEventArgs) Handles DataGridView1.DataBindingComplete
              For Each row As DataGridViewRow In Me.DataGridView1.Rows
                  Dim cell As DataGridViewComboBoxCell = TryCast(row.Cells("Match"), DataGridViewComboBoxCell)
                  cell.DataSource = Me.Groups.Where(Function(g) g.Members.Contains(row.Cells("Foo").Value.ToString())).ToList()
                  cell.Value = cell.Items(0).ID ' Same property as combocell.ValueMember
              Next
          End Sub
      
          Private Function InitializeGroups() As List(Of Group)
              Dim groups = New List(Of Group)() From { _
                  New Group() With { _
                      .ID = 1, _
                      .Name = "All", _
                      .Members = New List(Of String)() From { _
                          "Me", _
                          "You", _
                          "Him", _
                          "Her", _
                          "It" _
                      } _
                  }, _
                  New Group() With { _
                      .ID = 2, _
                      .Name = "Them", _
                      .Members = New List(Of String)() From { _
                          "Him", _
                          "Her", _
                          "It" _
                      } _
                  }, _
                  New Group() With { _
                      .ID = 3, _
                      .Name = "Us", _
                      .Members = New List(Of String)() From { _
                          "Me", _
                          "You" _
                      } _
                  }, _
                  New Group() With { _
                      .ID = 4, _
                      .Name = "Me", _
                      .Members = New List(Of String)() From { _
                          "Me" _
                      } _
                  }, _
                  New Group() With { _
                      .ID = 5, _
                      .Name = "Human", _
                      .Members = New List(Of String)() From { _
                          "Me", _
                          "You", _
                          "Him", _
                          "Her" _
                      } _
                  }, _
                  New Group() With { _
                      .ID = 6, _
                      .Name = "Non-human", _
                      .Members = New List(Of String)() From { _
                          "It" _
                      } _
                  } _
              }
      
              Return groups
          End Function
      End Class
      
      Public Class Example
          Public Sub New(foo__1 As String, bar__2 As String)
              Foo = foo__1
              Bar = bar__2
          End Sub
      
          Public Property Foo() As String
              Get
                  Return m_Foo
              End Get
              Set(value As String)
                  m_Foo = Value
              End Set
          End Property
          Private m_Foo As String
          Public Property Bar() As String
              Get
                  Return m_Bar
              End Get
              Set(value As String)
                  m_Bar = Value
              End Set
          End Property
          Private m_Bar As String
      End Class
      
      Public Class Group
          Public Sub New()
              Me.Members = New List(Of String)()
          End Sub
      
          Public Property ID() As Integer
              Get
                  Return m_Id
              End Get
              Set(value As Integer)
                  m_Id = value
              End Set
          End Property
          Private m_Id As String
          Public Property Name() As String
              Get
                  Return m_Name
              End Get
              Set(value As String)
                  m_Name = Value
              End Set
          End Property
          Private m_Name As String
          Public Property Members() As List(Of String)
              Get
                  Return m_Members
              End Get
              Set(value As List(Of String))
                  m_Members = Value
              End Set
          End Property
          Private m_Members As List(Of String)
      End Class
      

      【讨论】:

      • 我不介意再次迭代 - 很好的例子。如何显示 DatagridViewComboBox 的选定值?
      • 其实只需要选中第一个项目(selectedindex = 0)。环顾互联网,看看这是如何完成的。 MS 并不容易。我得到了 row.Cells("Match").Value = ???部分,但似乎无法获得组合框的第一个值
      • 好的 - 到目前为止,无法设置 dgvComboBox 的选定索引(啊!),但可以设置 dgvComboBox 使用的单元格本身的值。所以我接近正确答案。我试过这个,但它不起作用: Dim itm As Group = DirectCast(cell.Items(0), Group) row.Cells("Match").Value = itm.Members(0).ToString
      • 我使用上面的代码得到的错误:“DataGridViewComboBoxCell 值无效。”拉了24小时的头发还是没有解决办法!
      • @MC9000 如此接近。试试cell.Value = cell.Items(0).Name。我将它添加到上面的代码示例中,运行时,它给出了预期的结果。 TBH 我认为它应该是 cell.Value = cell.Items(0),但是 magic.
      猜你喜欢
      • 1970-01-01
      • 2021-08-15
      • 2014-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-08
      • 2020-12-25
      • 2021-09-23
      相关资源
      最近更新 更多