如何为每个记录的 DataGridViewComboBox 分配不同的数据源?
How do you assign different data sources for a DataGridViewComboBox for each record?
我有一个 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 的数据绑定,这样我就可以从另一个单元格获取值(以调用另一个过程),然后使用 return 数据填充每一行的组合框。这很简单 w/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
这是一个 C# 示例,说明如何在具有不同 Types
.
的 DataGridView
中使用 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();
}
}
解决方案
使用 DataBindingComplete
事件处理程序遍历您的行并为每个行设置源 DataGridViewComboBoxCell
。
例子
下面是我如何执行此操作的示例。您需要添加一个 DataGridView
和一个 ComboBox
(有两个选项,即 "option 1" 和 "option 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
那好吧!这是一个可行的解决方案。我发现您必须以编程方式创建您的 DataGridView(乏味,是的!)并关闭列的自动生成(绝对必须) - 这可以防止多次触发 dataGridView 事件。它还可以防止丢失组合框的数据源。使用 DataBindingComplete 事件并解析其中的行是执行此操作的最佳方法(CellFormatting 事件太过分了,被称为 w/every 鼠标移动、单击、调整大小等)。
对于我们这些使用对象而不是数据表的人来说,我希望这个解决方案可用。
代码:
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
我有一个 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 的数据绑定,这样我就可以从另一个单元格获取值(以调用另一个过程),然后使用 return 数据填充每一行的组合框。这很简单 w/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
这是一个 C# 示例,说明如何在具有不同 Types
.
DataGridView
中使用 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();
}
}
解决方案
使用 DataBindingComplete
事件处理程序遍历您的行并为每个行设置源 DataGridViewComboBoxCell
。
例子
下面是我如何执行此操作的示例。您需要添加一个 DataGridView
和一个 ComboBox
(有两个选项,即 "option 1" 和 "option 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
那好吧!这是一个可行的解决方案。我发现您必须以编程方式创建您的 DataGridView(乏味,是的!)并关闭列的自动生成(绝对必须) - 这可以防止多次触发 dataGridView 事件。它还可以防止丢失组合框的数据源。使用 DataBindingComplete 事件并解析其中的行是执行此操作的最佳方法(CellFormatting 事件太过分了,被称为 w/every 鼠标移动、单击、调整大小等)。 对于我们这些使用对象而不是数据表的人来说,我希望这个解决方案可用。
代码:
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