0

我用DataGridViewComboBoxColumnDataGridView. 我需要的是ComboBox根据每个 Row ID过滤值。

Si 它应该看起来像

-----------------------------
Row ID       ComboBox
              Values
            ID    Name
-----------------------------
1            1     A
             2     B
-----------------------------               
2            3     C
             4     D
-----------------------------

所以我所做的是DataGridViewComboBoxColumn用空创建,DataSource如下面的代码所示

var d = new DataGridViewComboBoxColumn()
{
 HeaderText = columnHeader,
 Width = 50,
 DataPropertyName = "D" + i.ToString(),
 DataSource = new BindingSource(){ DataSource = new List<WorkTypeItem>() },
 ValueMember = "ID",
 DisplayMember = "Name",
 Name = "D" + i.ToString()
};
dgvCalendar.Columns.Add(d);

我假设为事件中的每个单元格 填充Row 。 ComboBoxCellFormatting

 private void DgvCalendar_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{

  // Get object bounded with Row  
  CalendarDetailView row = dgvCalendar.Rows[e.RowIndex].DataBoundItem as CalendarDetailView;

  // By row ID  filter list for cell ComboBox
  var workItems = MyWorkItems.Where(x => x.ID == row.ID); 

  // So how we can to populate cell ComboBox now?
  dgvCalendar.Rows[e.RowIndex].Cells[1] ..... ??? = workItems ;


}

我这样做是因为我无法在单元格ComboBox中显示所有可能的值,因为它们不适合每一行。所以这个想法不是在ComboBox中显示 1000 个值,而是只显示Row ID引用的值。

我的目标是每个单元格都有自己的值列表,但来自同一个 List()。

任何线索如何做到这一点?


更新#1

感谢Marco Guignard ,我刚刚开始编写代码!我只是为 C# 版本更新它。

private void DgvCalendar_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
   if (e.Control is ComboBox)
   {
        int currentKey = (int)dgvCalendar.CurrentRow.Cells[dgvCalendar.CurrentCell.ColumnIndex].Value;

        ComboBox editor = (ComboBox)e.Control;
        CalendarDetailView row = dgvCalendar.CurrentRow.DataBoundItem as CalendarDetailView;

       var filteredItems = WorkTypes.Where(x =>x.ID = row.ID).ToList();

       editor.DataSource = filteredItems;
        editor.SelectedValue = currentKey;
   }           
}

更新#2

实际上,我已经用类似的方法完成了它,但使用了不同的事件。

因此,最初在列创建逻辑上,我使用数据库表中所有可能的记录来初始化DataGridView值,并在DataGridView出现时看到它。

当我们必须编辑组合框单元格时,我们只需应用对象允许值列表。

private void DgvCalendar_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
    {
        if (dgvCalendar.Columns[e.ColumnIndex].Name.StartsWith("D"))
        {
           var isComboBox = dgvCalendar.CurrentCell is DataGridViewComboBoxCell;
           if (isComboBox)
           {
               DataGridViewComboBoxCell dgViewComboBoxCell = dgvCalendar.CurrentCell as DataGridViewComboBoxCell;

               CalendarDetailView row = dgvCalendar.Rows[e.RowIndex].DataBoundItem as CalendarDetailView;

               dgViewComboBoxCell.DataSource = new BindingSource()
               {
                 DataSource = row.WorkTypes
               };
          }
      }
    }
4

1 回答 1

1

您必须处理 EditingControlShowing 事件。

首先,您必须检查 datagridview 的 CurrentCell 列是否对应于组合框列。然后,您可以根据需要更改组合框编辑器数据源。

不要忘记保留一个全局列表作为列的数据源,因为它仍将用于显示单元格!

这是 VB.NET 中的示例(不需要 FixupDropDownWidth,它只是为了更好的 UI 显示而获得的奖励)。

        Private Sub DataGridView_EditingControlShowing(sender As System.Object, e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DataGridView.EditingControlShowing
                'Route the event depending the cells being edited
                Try
                    If Me.DataGridView.CurrentCell.OwningColumn Is Me.DataGridView.Columns("comboboxcolumnname") Then
                        comboboxcolumnname_EditingControlShowing(sender, e)
                    End If
                Catch ex As Exception
    'Exception handling...
                End Try
            End Sub

    Private Sub comboboxcolumnname_EditingControlShowing(sender As System.Object, e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs)
        Dim editor As ComboBox = CType(e.Control, ComboBox)
        Dim currentKey As Short = Me.DataGridView.CurrentRow.Cells("comboboxcolumnname").Value

        'Filter editor datasource, remove inactives items except current
        Dim listObject As New List(Of Object)
        listObject.AddRange(GlobalList.Where(Function(c) c.FilterCondition = True OrElse c.ID = currentKey).OrderBy(Function(c) c.Name))
        editor.DataSource = listObject

        editor.SelectedValue = currentKey

        'Adapt the width of the DropDown
        CType(Me.DataGridView.Columns("comboboxcolumnname"), DataGridViewComboBoxColumn).FixupDropDownWidth(listObject)
    End Sub

 <Extension()>
    Public Sub FixupDropDownWidth(column As DataGridViewComboBoxColumn, items As IEnumerable)
        Dim width As Integer = column.DropDownWidth

        Dim vertScrollBarWidth As Integer = 0
        If column.Items.Count > column.MaxDropDownItems Then vertScrollBarWidth = SystemInformation.VerticalScrollBarWidth

        Dim g As Graphics = column.DataGridView.CreateGraphics()
        Dim font As Font

        font = column.DefaultCellStyle.Font
        If font Is Nothing Then font = column.DataGridView.Font

        Dim maxWidth As Integer = 0
        For Each item In items
            Dim stringValue As String
            If item.GetType.GetProperty(column.DisplayMember) IsNot Nothing Then
                stringValue = CStr(item.GetType().GetProperty(column.DisplayMember).GetValue(item, Nothing))
            Else
                stringValue = item.ToString
            End If
            maxWidth = g.MeasureString(CStr(stringValue), font).Width + vertScrollBarWidth
            If width < maxWidth Then width = maxWidth
        Next

        column.DropDownWidth = width
    End Sub
于 2017-08-23T09:27:30.877 回答