devExpress searchLookupEdit not setting value - vb.net

I have multiple searchLookupEdit controls on a form. All but one are working.
here is the code to populate one that is working
Private _list As sbList
_list = ag.ListByName("RMATroubleCode")
sluTroubleCode.Properties.DataSource = _list.Items
sluTroubleCode.EditValue = _item.TroubleCode.Value
here is the one that will not work
Private Sub populate_SKUOrdered(ByRef ctl As SearchLookUpEdit)
Dim ag As New cpAssemblyQuery()
Dim l As List(Of cpAssembly) = ag.TopLevelAssemblies()
ctl.Properties.DataSource = l
End Sub
populate_SKUOrdered(sluCreateSKUOrdered)
sluCreateSKUOrdered.EditValue = _item.SKU_OriginallyOrdered.Value
I have verified that sluCreateSKUOrdered has a DisplayMember and ValueMember property set correctly. They are both set to "SKU" so that is pretty simple.
The dropdown does contain the expected # of items.
The SKU i am trying to set is 'RM45'. So thats pretty simple to verify. It is not a case of trailing or leading spaces...
Are there some trouble shooting steps I can take? I am confident this is a case of simple oversight, but I can not find anything on DevExpress to help me resolve this issue.

I am using a ORM, it is necessary to use the following code
ctl.Properties.DisplayMember = "SKU.Value"
ctl.Properties.ValueMember = "SKU.Value"
The other controls were using interfaces, or simpler objects, so there was not a good analogy there.

Related

How to check datagridview column already exists with same Header Text Before adding a new Column in VB.net

I am trying to add columns dynamically to data grid view using VB.net. But the issue is I need to check that the column name already exists. before adding it if exists I want it to be cancelled automatically. I am using another form to select the Job Nos. which will add as Datagridview Header Text when it saved. () below is the code I am using to add a column to my datagridview. Hope you understand the question. I found some nearby answers in C# unfortunately I am not able to convert those correctly as my C# coding knowledge is little weak.
Thank You!
Dim FRMP = FrmEReview.ReviewGrid.Columns
Dim NOHRS As New DataGridViewTextBoxColumn
FRMP.Add(NOHRS)
NOHRS.HeaderText = Me.Cmb_CName.Text & "-" & Me.Cmb_DName.Text
NOHRS.Width = 160
The obvious option - the one you should have been able to work out for yourself - is to simply loop through the columns and test the HeaderText of each one:
Dim headerText = $"{Cmb_CName.Text}-{Cmb_DName.Text}"
Dim headerTextFound = False
For Each column As DataGridViewColumn In FrmEReview.ReviewGrid.Columns
If column.HeaderText = headerText Then
headerTextFould = True
Exit For
End If
Next
If Not headerTextFound Then
'...
End If
This is basically the code equivalent of what you'd do manually, which is why you should have been able to do it for yourself, at least mostly.
The not-so-obvious solution for a beginner is to use LINQ. LINQ is basically a means to flatten loops like this, so it leads to far more succinct code:
Dim headerText = $"{Cmb_CName.Text}-{Cmb_DName.Text}"
If FrmEReview.ReviewGrid.
Columns.
Cast(Of DataGridViewColumn)().
All(Function(dgvc) dgvc.HeaderText <> headerText) Then
'...
End If

Quicker method than looping through thousands of records

Is there a quicker way than looping through thousands of records (around 24k)?
Code:
For n = 0 To oCHStockItems.Count - 1
Dim itemSellingPrice As New CH.CH_ItemSellingPrice
With itemSellingPrice
.StockItem = oCHStockItems(n).StockItem
.Code = oCHStockItems(n).StockItem.Code
.Name = oCHStockItems(n).StockItem.Name
.ProductGroupCode = oCHStockItems(n).StockItem.ProductGroup.Code
.CurrentSellingPrice = oCHStockItems(n).StockItem.StockItemPrices(0).Price
.NewSellingPrice = 0D
.LastSellingPriceDate = oCHStockItems(n).LastSellingPriceDate
.OriginalPrice = oCHStockItems(n).OriginalPrice
End With
_itemSellingPrices.Add(itemSellingPrice)
Next
Originally I was assigning oCHStockItems to a Grid (it's actually a Sage 200 Grid) however I can't seem to find a way to reference to the field oCHStockItems(n).StockItem.StockItemPrices(0).Price.
Normally the above kind of syntax works. For example if I want to reference to the Stock Code it would be StockItem.Code.
StockItem.StockItemPrices(0).Price does produce a value however it doesn't show on the Grid. I've logged a ticket with Sage to see if they can help.
However I'm thinking they will come back and say that it can't be done and on that assumption I'm kind of left with looping through oStockItems and assigning the properties to the properties of my predefined class. So with that in mind has anyone any suggestions of speeding this kind of process up?
Sage got back to me with a solution:
First:
AddHandler dgItems.Items.ItemAdded, AddressOf Items_ItemAdded
Then:
Private Sub Items_ItemAdded(ByVal sender As Object, ByVal args As Sage.Common.Controls.ListItemArgs)
args.Item.SubItems(4).Value = oCHStockItems(args.Item.Index).StockItem.StockItemPrices(0).Price
End Sub
This quickly populates the item on the Grid.
All I have done is assign the original collection oCHStockItems to the .DataSource of the grid and the method Items_ItemAdded sorts the rest out.

VB.Net Access Variables in a Generic Form Object

My company have put me on an urgent project to update one of our existing programs from VB6 to VB.Net. This is happening in two stages, the first of which I personally see as a waste of time, but it's being insisted it be done, is to use the conversion process within Visual Studio and then clean-up errors just to get a compiled version. The size of the program is huge, but as I don't have a say at this point I'm trying to work through the hundreds of compiler errors. I do realise that what I'm doing isn't best practice and is quite a frustrating situation/waste of time.
Basically there are a number of forms, one of which can call any number of other forms, which is dictated by an If statement. When the form is loaded, variables within the new form as assigned and it opens. Some of the variables are commonly named, others are not. So in the VB6 code it would look something like this:
Dim frm As System.Windows.Forms.Form
If x=y Then
frm = New frm1
frm.Variable1 = "VarA"
frm.Variable2 = "VarB"
Else
frm = New frm2
frm.Variable3 = "VarC"
frm.Variable4 = "VarD"
End If
frm.Variable5 = "VarE"
I toyed with putting a separate form object within the If statements, but as they are needed outside of it as well, it doesn't really solve the issue, and as the generic items are used so much for other aspects it wouldn't be practical to duplicate them all within separate assignments.
I was hoping there would be a quick solution along the lines of
frm.Var("Variable1") = "VarA"
But I've not been able to find anything that could be simply implemented across such a large amount of conditions.
Apologies for not encouraging the best practice, because I do realise that any solution wouldn't be it, but I am looking for the quickest implementation so that I can move on to just rewriting the whole program.
The ugly, but simplest solution is to add the line Option Strict Off to the top of any file that does that kind of thing. When Option Strict is turned off, VB.NET will perform the same kind of late-binding operation as VB6. If, at runtime, it discovers that the member name is invalid, it will throw an exception, but as long as the member exists and has the expected signature, it will work. This is typically bad-practice, in my opinion, but in a situation like this, sometimes it can be warranted.
As a side-note, what it's actually doing when you have Option Strict Off is it is using reflection to find the member by the specified name. Technically, you could use reflection manually, yourself, but it requires more code to do the same thing, which is precisely what you seem to be trying to avoid.
If you don't want to do that, you can use CType or DirectCast to cast the object to the specific type. For instance:
Dim frm As System.Windows.Forms.Form
If x=y Then
frm = New frm1
DirectCast(frm, frm1).Variable1 = "VarA"
DirectCast(frm, frm1).Variable2 = "VarB"
Else
frm = New frm2
DirectCast(frm, frm2).Variable3 = "VarC"
DirectCast(frm, frm2).Variable4 = "VarD"
End If
frm.Variable5 = "VarE"
Or you could create a variable of the correct type like this:
Dim frm As System.Windows.Forms.Form
If x=y Then
Dim f As New frm1
f.Variable1 = "VarA"
f.Variable2 = "VarB"
frm = f
Else
Dim f As New frm2
f.Variable3 = "VarC"
f.Variable4 = "VarD"
frm = f
End If
frm.Variable5 = "VarE"

How can I use value of a string to control another control in VB.net?

I have been playing around with some code, and I have made easily 50+ controls that all are labeled: PictureBox[XCoordinate]_[YCorrdinate] (Replacing the brackets and contents with the coordinates of them on a little grid I made.)
The problem with this is it is a real pain to use a control when doing loops to update all the picture boxes. I want to know how to do code like:
'This code assumes that the picture boxes are all initialized.
Dim XCoordiante As Integer = 5
Dim YCorrdinate As Integer = 2
PictureBox[XCoordinate]_[YCoordiante].Image = [Put Image Here]
I am going to put this within a loop. Is there a way that I can do this without manually typing it all and risking missing something within a case statement? And also, I would have to retype it for every different kind of change I want to make (ex: tag or error image).
Would a pointer somehow help? I don't really know how to do this, but it would be really helpful if possible.
When you create them, save them to a List:
Private pList As New List(Of PictureBox)
Dim pic As New PictureBox
With Pic
.Location = ...
' etc
End With
Me.Controls.Add(pic)
pList.Add(pic)
Assuming they are created in some sort of order:
For n As integer = 0 To pList.Count = 1
' add code to look at Plist(n).X and .Y to determine what to do (?)
Plist(n).Image = ...
Next n
If there is more info to capture, create a custom class of a PicBox and the other info, and make the list a List(Of myPicClass).

ComboBox DataBinding DisplayMember and LINQ queries

Update
I decided to iterate through the Data.DataTable and trimmed the values there.
Utilizing SirDemon's post, I have updated the code a little bit:
Sub test(ByVal path As String)
Dim oData As GSDataObject = GetDataObj(path)
EmptyComboBoxes()
Dim oDT As New Data.DataTable
Try
Dim t = From r In oData.GetTable(String.Format("SELECT * FROM {0}gsobj\paths ORDER BY keyid", AddBS(path))) Select r
If t.Count > 0 Then
oDT = t.CopyToDataTable
For Each dr As Data.DataRow In oDT.Rows
dr.Item("key_code") = dr.Item("key_code").ToString.Trim
dr.Item("descript") = dr.Item("descript").ToString.Trim
Next
dataPathComboBox.DataSource = oDT
dataPathComboBox.DisplayMember = "descript"
dataPathComboBox.ValueMember = "key_code"
dataPathComboBox.SelectedIndex = 0
dataPathComboBox.Enabled = True
End If
Catch ex As Exception
End Try
End Sub
This works almost as I need it to, the data is originally from a foxpro table, so the strings it returns are <value> plus (<Field>.maxlength-<value>.length) of trailing whitespace characters. For example, a field with a 12 character length has a value of bob. When I query the database, I get "bob_________", where _ is a space.
I have tried a couple of different things to get rid of the whitespace such as:
dataPathComboBox.DisplayMember.Trim()
dataPathComboBox.DisplayMember = "descript".Trim.
But nothing has worked yet. Other than iterating through the Data.DataTable or creating a custom CopyToDataTable method, is there any way I can trim the values? Perhaps it can be done in-line with the LINQ query?
Here is the code I have so far, I have no problem querying the database and getting the information, but I cannot figure out how to display the proper text in the ComboBox list. I always get System.Data.DataRow :
Try
Dim t = From r In oData.GetTable("SELECT * FROM ../gsobj/paths ORDER BY keyid") _
Select r
dataPathComboBox.DataSource = t.ToList
dataPathComboBox.SelectedIndex = 0
'dataPathComboBox.DisplayMember = t.ToList.First.Item("descript")
dataPathComboBox.Enabled = True
Catch ex As Exception
Stop
End Try
I know that on the DisplayMember line the .First.Item() part is wrong, I just wanted to show what row I am trying to designate as the DisplayMember.
I'm pretty sure your code tries to set an entire DataRow to a property that is simply the name of the Field (in a strongly type class) or a Column (in a DataTable).
dataPathComboBox.DisplayMember = "descript"
Should work if the DataTable contains a retrieved column of that name.
Also, I'd suggest setting your SelectedIndex only AFTER you've done the DataBinding and you know you actually have items, otherwise SelectedIndex = 0 may throw an exception.
EDIT: Trimming the name of the bound column will trim just that, not the actual bound value string. You either have to go through all the items after they've been bound and do something like:
dataPathComboBox.Item[i].Text = dataPathComboBox.Item[i].Text.Trim()
For each one of the items. Not sure what ComboBox control you're using, so the item collection name might be something else.
Another solution is doing that for each item when it is bound if the ComboBox control exposes an onItemDataBound event of some kind.
There are plenty of other ways to do this, depending on what the control itself offers and what you choose to do.
DisplayMember is intended to indicate the name of the property holding the value to be displayed.
In your case, I'm not sure what the syntax will by since you seem to be using a DataSet, but that should be
... DisplayMember="Item['descript']" ...
in Xaml, unless you need to switch that at runtime in which case you can do it in code with
dataPathComboBox.DisplayMember = "Item['descript']"
Again, not 100% sure on the syntax. If you are using a strongly typed DataSet it's even easier since you should have a "descript" property on your row, but given hat your error indicates "System.DataRow" and not a custom type, I guess you are not.
Because I can't figure out the underlying type of the datasource you are using I suggest you to change commented string to
dataPathComboBox.DisplayMember = t.ElementType.GetProperties.GetValue(0).Name
and try to determine correct index (initially it is zero) in practice.