如何根据行 ID 填充 ComboBox DataGridView
How to populate ComboBox DataGridView depending on Row ID
我在DataGridView
中使用DataGridViewComboBoxColumn
。
我需要的是根据每一行过滤 ComboBox
值 ID.
它应该是这样的
-----------------------------
Row ID ComboBox
Values
ID Name
-----------------------------
1 1 A
2 B
-----------------------------
2 3 C
4 D
-----------------------------
所以我所做的是用空 DataSource
创建 DataGridViewComboBoxColumn
它已在下面的代码中显示
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);
并且我假设为 CellFormatting
事件中的每个单元格填充 行 ComboBox
。
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 中显示所有可能的值,因为它们不适合每一行。所以这个想法不是显示 1000
ComboBox 中的值,但只有 Row ID.
引用的值
我的 objective 是每个单元格都有自己的值列表,但来自同一个 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
实际上我用类似的方法完成了它,但使用了不同的事件。
所以最初在列创建逻辑上,我使用数据库 table 中所有可能的记录来用值初始化 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
};
}
}
}
您必须处理 EditingControlShowing 事件。
首先您必须检查您的datagridview 的CurrentCell 列是否对应于combobox 列。然后您可以根据需要更改组合框编辑器数据源。
不要忘记保留一个全局列表作为列的数据源,因为它仍将用于显示单元格!
这是 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
我在DataGridView
中使用DataGridViewComboBoxColumn
。
我需要的是根据每一行过滤 ComboBox
值 ID.
它应该是这样的
-----------------------------
Row ID ComboBox
Values
ID Name
-----------------------------
1 1 A
2 B
-----------------------------
2 3 C
4 D
-----------------------------
所以我所做的是用空 DataSource
创建 DataGridViewComboBoxColumn
它已在下面的代码中显示
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);
并且我假设为 CellFormatting
事件中的每个单元格填充 行 ComboBox
。
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 中显示所有可能的值,因为它们不适合每一行。所以这个想法不是显示 1000 ComboBox 中的值,但只有 Row ID.
引用的值我的 objective 是每个单元格都有自己的值列表,但来自同一个 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
实际上我用类似的方法完成了它,但使用了不同的事件。
所以最初在列创建逻辑上,我使用数据库 table 中所有可能的记录来用值初始化 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
};
}
}
}
您必须处理 EditingControlShowing 事件。
首先您必须检查您的datagridview 的CurrentCell 列是否对应于combobox 列。然后您可以根据需要更改组合框编辑器数据源。
不要忘记保留一个全局列表作为列的数据源,因为它仍将用于显示单元格!
这是 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