Linq to SQL in VS 2019 using VB.NET - Outer left join? - vb.net

I'm struggling to get the result I need from my linq to SQL query. I can find all of the person table records, or only the ones that have a corresponding date_table entry. This is the query I'm using, this results in only MK numbers 101 and 104 being returned. Numbers 100 and 105 are missed I guess because they don't have a valid record for today?
Where Person_data_table.MK = Date_Table.FK And Date_Table.Allocated <> "Vacation" And Date_Table.Allocated <> "Sick" And Date_Table.Date = Today And Person_data_table.Team = "A"
This is the table data (note Today is 15-Mar-20) - Please keep answers in VB, as C# answers don't tend to work after I have translated them! - Any help appreciated
regards
Peter

Notice that you also posted your question here.
Is your question still unresolved? You can try my code as follows. Sorry I didn't use SQL, I used class, but that didn't affect the result.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim MK100 As NewPerson = New NewPerson With {
.MK = "100",
.First_Name = "Mike",
.Last_Name = "Smith",
.Team = "A"
}
Dim MK101 As NewPerson = New NewPerson With {
.MK = "101",
.First_Name = "Dave",
.Last_Name = "Sharp",
.Team = "A"
}
Dim MK102 As NewPerson = New NewPerson With {
.MK = "102",
.First_Name = "Roger",
.Last_Name = "Hands",
.Team = "A"
}
Dim MK103 As NewPerson = New NewPerson With {
.MK = "103",
.First_Name = "Keely",
.Last_Name = "Riller",
.Team = "A"
}
Dim MK104 As NewPerson = New NewPerson With {
.MK = "104",
.First_Name = "Simon",
.Last_Name = "Says",
.Team = "A"
}
Dim MK105 As NewPerson = New NewPerson With {
.MK = "105",
.First_Name = "Eugene",
.Last_Name = "Phillips",
.Team = "A"
}
Dim MK106 As NewPerson = New NewPerson With {
.MK = "106",
.First_Name = "William",
.Last_Name = "Nobody",
.Team = "B"
}
Dim FK101 As NewDate = New NewDate With {
.FK = "101",
.Date_ = "15-Mar-20",
.Allocated = "Job Number 1"
}
Dim FK102 As NewDate = New NewDate With {
.FK = "102",
.Date_ = "15-Mar-20",
.Allocated = "Vacation"
}
Dim FK103 As NewDate = New NewDate With {
.FK = "103",
.Date_ = "15-Mar-20",
.Allocated = "Sick"
}
Dim FK104 As NewDate = New NewDate With {
.FK = "104",
.Date_ = "15-Mar-20",
.Allocated = "Job nunber 2"
}
Dim Person_Data_table As List(Of NewPerson) = New List(Of NewPerson) From {
MK100,
MK101,
MK102,
MK103,
MK104,
MK105,
MK106
}
Dim Date_Table As List(Of NewDate) = New List(Of NewDate) From {
FK101,
FK102,
FK103,
FK104
}
Dim query = From NewPerson In Person_Data_table Group Join NewDate In Date_Table On NewPerson.MK Equals NewDate.FK Into gj = Group From subperson In gj.DefaultIfEmpty() Where (NewPerson.Team = "A") AndAlso (subperson Is Nothing OrElse ((subperson.Allocated <> "Vacation") AndAlso (subperson.Allocated <> "Sick"))) Select New With {NewPerson.MK, NewPerson.First_Name, NewPerson.Last_Name, NewPerson.Team
}
For Each v In query
ListBox1.Items.Add($"{v.MK,-15}{v.First_Name,-15}{v.Last_Name,-15}{v.Team}")
Next
End Sub
End Class
Class NewPerson
Public Property MK As String
Public Property First_Name As String
Public Property Last_Name As String
Public Property Team As String
End Class
Class NewDate
Public Property FK As String
Public Property Date_ As String
Public Property Allocated As String
End Class
And the effect is as follows:

Related

Dictionary (of integer,class) type

I would like to save variables in a simple method before adding to a datatable. Is it possible to have a dictionary (of integer,class) type like the code below? I can then loop through the keys to get the variables.Any ideas please?
Public Class CONTACTS
Dim FIRST_NAME As String
Dim SURNAME As String
Dim DOB As Date
Dim AGE As Integer
End Class
Sub TEST_DICT()
Dim dctCONTACTS As Dictionary(Of Integer, List OF Class(CONTACTS)) 'not sure how to declare this
dctCONTACTS.Add(1, "MARK").FIRST_NAME 'not sure how to savevariable
dctCONTACTS.Add(1, "SMITH").SURNAME
dctCONTACTS.Add(1, "5 May 1995").DOB
dctCONTACTS.Add(1, 31).AGE
dctCONTACTS.Add(2, "ANNE").FIRST_NAME
dctCONTACTS.Add(2, "MOORE").SURNAME
dctCONTACTS.Add(3, "5 April 1990").DOB
dctCONTACTS.Add(4, 26).AGE
Dim X = dctCONTACTS(1).AGE
End Sub
You really you go look at the many many "how to code VB.NET" resources online rather than ask basic syntax questions here.
Here is your code in valid VB.NET:
Public Class CONTACTS
Public FIRST_NAME As String
Public SURNAME As String
Public DOB As Date
Public AGE As Integer
End Class
Sub TEST_DICT()
Dim dctCONTACTS As New Dictionary(Of Integer, List(Of CONTACTS))
dctCONTACTS.Add(1, New List(Of CONTACTS) From
{
New CONTACTS() With { .FIRST_NAME = "MARK", .SURNAME = "SMITH", .DOB = New DateTime(1995, 5, 5), .AGE = 31 },
New CONTACTS() With { .FIRST_NAME = "JOE", .SURNAME = "SMITH", .DOB = New DateTime(1995, 5, 5), .AGE = 31 },
New CONTACTS() With { .FIRST_NAME = "SARAH", .SURNAME = "SMITH", .DOB = New DateTime(1995, 5, 5), .AGE = 31 }
})
dctCONTACTS.Add(2, New List(Of CONTACTS) From
{
New CONTACTS() With { .FIRST_NAME = "BOB", .SURNAME = "SMITH", .DOB = New DateTime(1995, 5, 5), .AGE = 31 },
New CONTACTS() With { .FIRST_NAME = "SUE", .SURNAME = "SMITH", .DOB = New DateTime(1995, 5, 5), .AGE = 31 },
New CONTACTS() With { .FIRST_NAME = "ABIGAIL", .SURNAME = "SMITH", .DOB = New DateTime(1995, 5, 5), .AGE = 31 }
})
Console.WriteLine(dctCONTACTS(2)(0).FIRST_NAME)
End Sub
Running TEST_DICT gives BOB in this case.

How do you assign different data sources for a DataGridViewComboBox for each record?

I have a winforms DataGridView that I wish to have a column containing comboboxes for each record. Each combobox will have completely different values for each row and need to be assigned a datasource during the databinding of the DataGridView. I can assign 1 datasource to all (that's easy), but having each combobox have different values looks impossible).
Here's what I'm working with - note: The datasource of the DataGridView is defined programmatically by setting a property from the calling form.
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
If there were some way to intercept the databinding of the DataGridView so I can get a value from another cell (to call another procedure), then use the return data to populate each row's combobox. This is easy w/webforms, but I don't see an event for the winforms version.
Another thing I've tried, but does not work (the combobox datasource just disappears!)
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
Here's another version of that same assignment, this time the combobox is populated with the add method. (STILL does not remember the values)
I basically followed another forum's idea - maybe DotNet 4.5 DataGridView has a bug in it.
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
Allrighty Then! Here's a working solution. What I discovered is that you must create your DataGridView programmatically (tedious, yes!) and turn off auto-generation of columns (absolute must) - this prevents multiple firings of dataGridView events, for one. It also prevents losing your datasource for your combobox. Using the DataBindingComplete event and parsing the rows within is the best way to do this (CellFormatting event is overkill and is called w/every mouse move, click, resize, etc).
For those of us working with objects instead of datatables, I hope this solution is usable.
The code:
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
Here's an example in C# on how to have a DataGridViewComboBoxColumn in a DataGridView with different Types.
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();
}
}
Solution
Use the DataBindingComplete event handler to iterate through your rows and set the source for each DataGridViewComboBoxCell.
Example
Here's an example of how I did this. You'll need to add a DataGridView and a ComboBox (with two options, i.e. "option 1" and "option 2", for switching the DataGridView.DataSource) to your 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

Get sales Orders between dates

How can I make a call to the Magento SOAP API v2 to get all of the sales orders between a set of dates in vb.net?
Here is what I have tried so far, but it returns 0 sales orders despite the fact that they are present.
Dim ae As associativeEntity = New associativeEntity()
ae.key = "status"
ae.value = "processing"
Dim params As filters = New filters
Dim dateFilter As complexFilter
dateFilter = New complexFilter()
dateFilter.key = "created_at"
Dim nestedFilterFrom As associativeMultiEntity = New associativeMultiEntity()
nestedFilterFrom.key = "gteq"
nestedFilterFrom.value = New String() {DateTime.Parse(fromDate).ToUniversalTime.ToString()}
dateFilter.value = nestedFilterFrom
Dim dateToFilter As complexFilter = New complexFilter()
Dim nestedFilterTo As associativeMultiEntity = New associativeMultiEntity()
nestedFilterTo.key = "lteq"
nestedFilterTo.value = New String() {DateTime.Parse(toDate).ToUniversalTime.ToString()}
dateToFilter.key = "created_at"
dateToFilter.value = nestedFilterTo
params.complex_filter = New complexFilter() {dateFilter, dateToFilter}
magentoWS.salesOrderList(sessionID, params)
I have been able to get the same code to work matching on status, like below.
Dim ae As associativeEntity = New associativeEntity
Dim params As filters = New filters()
ae.key = "status"
ae.value = "processing"
params.filter = New associativeEntity() {ae}
magentoWS.salesOrderList(sessionID, params)
The date format must be the following for the filters to work.
YYYY-MM-DD
I only discovered this, because that is how it was in Magento's SOAP "v2" XML Request example. It would have been nice to specify this in the documentation or in their response, but se la vie. In case anyone is interested, here is the code.
Dim ae As associativeEntity = New associativeEntity With { .key = "status", .value = "processing" }
Dim params As filters = New filters
Const createdAt As String = "created_at"
Const magentoDateTimeFormat As String = "yyyy-MM-dd"
Dim nestedFilterFrom As associativeMultiEntity =
New associativeMultiEntity With {.key = "from", .value = New String() {fromDate.ToString(magentoDateTimeFormat)}}
Dim dateFromFilter As complexFilter = New complexFilter With {.key = createdAt, .value = nestedFilterFrom}
Dim nestedFilterTo As associativeMultiEntity =
New associativeMultiEntity With {.key = "to", .value = New String() {toDate.ToString(magentoDateTimeFormat)}}
Dim dateToFilter As complexFilter = New complexFilter With {.key = createdAt, .value = nestedFilterFrom}
params.complex_filter = New complexFilter() {dateFromFilter, dateToFilter}
magentoWS.salesOrderList(sessionID, params)
It should be noted that in this case, the from and to filters are equivalent to the lteq and gteq. I found from and to to make more sense in this context but results are the same.
Public Function getMageOrdersListByFilter(ByVal fromDate As DateTime, ByVal toDate As DateTime) As MagentoService.salesOrderListEntity()
GetMageSessionId()
Dim f As MagentoService.filters = New MagentoService.filters
Const createdAt As String = "created_at"
Dim magentoDateTimeFormat As String = "yyyy-MM-dd"
magentoDateTimeFormat = "yyyy-MM-dd HH:mm:ss"
Dim cpf(2) As MagentoService.complexFilter
cpf(0) = New MagentoService.complexFilter With {.key = createdAt, .value = New MagentoService.associativeEntity With {.key = "from", .value = New String(fromDate.ToString(magentoDateTimeFormat))}}
'HACK FIX: http://www.magentocommerce.com/bug-tracking/issue?issue=8073
cpf(1) = New MagentoService.complexFilter With {.key = "/*fake*/created_at", .value = New MagentoService.associativeEntity With {.key = "to", .value = New String(toDate.ToString(magentoDateTimeFormat))}}
f.complex_filter = cpf
Dim oList() As MagentoService.salesOrderListEntity = Nothing
Try
oList = mage.salesOrderList(sessionId, f)
Catch ex As Exception
End Try
Return oList
End Function

Multiple Parameters in LINQ to SQL

I am trying to pass several search parameters to an LINQ expression to retrieve all entries that contain one of the search items.
Example:
Dim query = From p In db.BEW_PROFIL
For Each searchItem As String In searchItems
Dim item As String = searchItem
query = query.Where(Function(p) p.NAME = item)
Next
Problem here is I don´t get any results because the Where clause looks with that code something like this.
... Where p.NAME = item1 AND p.NAME = item2
What i need is an OR between the parameters, but I don´t get it how I can achieve this.
Any help would be greatly appreciated.
Got it...
void Main()
{
var searchItems = new string[] { "test", "past", "most", "last", "fast", "feast", "yeast", "cast" };
var query = from p in searchItems select new MyClass { Name = p };
Predicate<MyClass> whereClause = _ => false;
foreach (var item in searchItems)
{
var searchItem = item;
Predicate<MyClass> oldClause = whereClause;
whereClause = p => p.Name == searchItem || oldClause(p);
}
query = query.Where(p => whereClause(p));
query.Dump();
}
public class MyClass
{
public MyClass() { }
public string Name { get; set; }
}
The code was ran in LINQPad, and that returned every element.
Here is that code translated to Vb.Net
Private Sub Main()
Dim searchItems = New String() {"test", "past", "most", "last", "fast", "feast", "yeast", "cast"}
Dim query = From p In searchItems Select New [MyClass]() With { .Name = p }
Dim whereClause As Predicate(Of [MyClass]) = Function(element) False
For Each item As String In searchItems
Dim searchItem = item
Dim oldClause As Predicate(Of [MyClass]) = whereClause
whereClause = Function(p) p.Name = searchItem OrElse oldClause(p)
Next
query = query.Where(Function(p) whereClause(p))
query.Dump()
End Sub
Public Class [MyClass]
Public Sub New()
End Sub
Public Property Name() As String
Get
Return m_Name
End Get
Set
m_Name = Value
End Set
End Property
Private m_Name As String
End Class

How to get Lambda in LINQ to actually filter for dynamic linq

Example-I have a person class
Public Class Person
Private _fname As String
Public Property Fname() As String
Get
Return _fname
End Get
Set(ByVal value As String)
_fname = value
End Set
End Property
Private _lname As String
Public Property Lname() As String
Get
Return _lname
End Get
Set(ByVal value As String)
_lname = value
End Set
End Property
Private _age As Integer
Public Property Age() As Integer
Get
Return _age
End Get
Set(ByVal value As Integer)
_age = value
End Set
End Property
End Class
Dim people As New List(Of Person)
people.Add(New Person With {.Fname = "Alice", .Lname = "Apples", .Age = 1})
people.Add(New Person With {.Fname = "Bob", .Lname = "Banana", .Age = 2})
people.Add(New Person With {.Fname = "Charlie", .Lname = "Cherry", .Age = 3})
people.Add(New Person With {.Fname = "Dave", .Lname = "Durian", .Age = 4})
people.Add(New Person With {.Fname = "Eric", .Lname = "EggPlant", .Age = 10})
Dim filteredPerson = From person In people
filteredPerson.Where(Function(fp) fp.Fname = "Bob")
Dim finalList = filteredPerson.ToList
For Each p In finalList
Debug.Print("FNAME: " + p.Fname)
Next
This still returns all 5 people, like the where is not being applied, what am I doing wrong?
I would also like to be able to pass a list of names and return only those
Dim searchList As New List(Of String)
searchList.Add("Bob")
searchList.Add("Dave")
Dim filteredPerson = From person In people
For Each s In searchList
Dim innerName As String = s
filteredPerson.Where(Function(fp) fp.Fname = innerName)
Next
Dim finalList = filteredPerson.ToList
For Each p In finalList
Debug.Print("FNAME: " + p.Fname)
Next
The problem is that Where doesn't change the collection. It returns the newly filtered collection.
Try this:
Dim filteredPerson = people.Where(Function(fp) fp.Fname = "Bob")
(By the way, I don't see anything dynamic in here... where are you using dynamic LINQ?)
To add multiple Where clauses, you'll want something like this:
Dim searchList As New List(Of String)
searchList.Add("Bob")
searchList.Add("Dave")
Dim filteredPerson As IEnumerable(Of String) = people
For Each s In searchList
Dim innerName As String = s
filteredPerson = filteredPerson.Where(Function(fp) fp.Fname = innerName)
Next
Dim finalList = filteredPerson.ToList
For Each p In finalList
Debug.Print("FNAME: " + p.Fname)
Next
However, I don't believe that's actually what you want to do. Each Where clause is going to insist that Fname is the specified name - and it's not going to be both Bob and Dave! I think you actually want something which can be expressed much more simply:
Dim searchList As New List(Of String)
searchList.Add("Bob")
searchList.Add("Dave")
Dim filteredPerson = people.Where(Function(fp) searchList.Contains(fp.Fname))
Dim finalList = filteredPerson.ToList
For Each p In finalList
Debug.Print("FNAME: " + p.Fname)
Next
All we want to know is whether Fname is in searchList, which is what Contains does.
Dim people As New List(Of Person)
people.Add(New Person With {.Fname = "Alice", .Lname = "Apples", .Age = 1})
people.Add(New Person With {.Fname = "Bob", .Lname = "Banana", .Age = 2})
people.Add(New Person With {.Fname = "Charlie", .Lname = "Cherry", .Age = 3})
people.Add(New Person With {.Fname = "Dave", .Lname = "Durian", .Age = 4})
people.Add(New Person With {.Fname = "Eric", .Lname = "EggPlant", .Age = 10})
Dim searchList As New List(Of String)
searchList.Add("Bob")
searchList.Add("Dave")
dim filteredItems = from p in people _
join i in searchList on p.FName equals i _
select p
dim personFound as Person
for each personFound in filteredItems
Console.WriteLine(personFound.Lname)
next