How do I reference a DIM Name (not value) in a function? - vb.net

I have a Dim publicly declared in my Form, how would I set/change the value of this Dim in a function without manually calling it like this: Test = "New Val"?
I would need it to be something like this:
Public Class Form2
Dim Test As String = "I do not want to read this value in the function,
I do however need to change this value"
Private Function PassingDimName(ByVal DimName As dim)
'Having it like this gives the following error:
'"Keyword does not name a type"
DimName = "Dims new value"
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
PassingDimName(Test)
End Sub
End Class

Use System.Reflection.GetField (String, BindingFlags) to access a field by name
Here are some functions for setting and getting field values:
Public Sub SetValue(name As String, value As Object)
Dim fi As FieldInfo = Me.GetType().GetField(name, BindingFlags.NonPublic Or BindingFlags.Instance)
fi.SetValue(Me, value)
End Sub
Public Function GetValue(name As String) As Object
Dim fi As FieldInfo = Me.GetType().GetField(name, BindingFlags.NonPublic Or BindingFlags.Instance)
Return fi.GetValue(Me)
End Function
Note: the BindingFlags are specific to your application, where you have declared a private field (Dim Test As ...). See BindingFlags Enumeration if you want to use something other than a private field.
In your specific implementation, you could set a new string to the field in the button click like this
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SetValue("Test1", "new value")
End Sub
A minimal, complete example to demonstrate how it works could look like this
Dim f2 = New Form2()
Console.WriteLine(f2.GetValue("Test1"))
Console.WriteLine(f2.GetValue("Test2"))
f2.SetValue("Test1", "new value")
f2.SetValue("Test2", 1)
Console.WriteLine(f2.GetValue("Test1"))
Console.WriteLine(f2.GetValue("Test2"))
with the form
Public Class Form2
Dim Test1 As String = "initial value"
Dim Test2 As Integer = 0
Public Sub SetValue(name As String, value As Object)
Dim fi As FieldInfo = Me.GetType().GetField(name, BindingFlags.NonPublic Or BindingFlags.Instance)
fi.SetValue(Me, value)
End Sub
Public Function GetValue(name As String) As Object
Dim fi As FieldInfo = Me.GetType().GetField(name, BindingFlags.NonPublic Or BindingFlags.Instance)
Return fi.GetValue(Me)
End Function
End Class
output:
initial value
0
new value
1
Another note: when setting the field, you aren't guaranteed to know the type. Trying f2.SetValue("Test2", "new value") would compile but would fail at runtime when trying to convert a string to an integer. If you know all your fields are strings, then it may be better to declare Public Sub SetValue(name As String, value As String) and Public Function GetValue(name As String) As String with the appropriate casts.

If you just want to change the value of the variable then change your function to this.
Private Sub PassingDimName(ByRef DimName As String)
'Having it like this gives the following error:
'"Keyword does not name a type"
DimName = "Dims new value"
End Sub

Related

Get a value by index from combobox class

i'm approaching to vbnet from vb6 and i'm triyng to get value from combobox using a class which contains the values i stored in.
here is the class
Private m_ItemText As String
Private m_ItemIndex As Int32
Public Sub New(ByVal strItemText As String, ByVal intItemIndex As Int32)
m_ItemText = strItemText
m_ItemIndex = intItemIndex
End Sub
Public ReadOnly Property ItemIndex() As Int32
Get
Return m_ItemIndex
End Get
End Property
Public ReadOnly Property ItemText() As String
Get
Return m_ItemText
End Get
End Property
I use this method charge the combobox
ComboBox2.Items.Add(New clsComboBoxItem("sometext", 1))
ComboBox2.Items.Add(New clsComboBoxItem("sometext 2", 2))
ComboBox2.Items.Add(New clsComboBoxItem("sometext", 3))
and this on combobox.selectedindexchanged
If ComboBox2.SelectedItem.GetType.ToString = itmCombo.GetType.ToString Then
itmCombo = CType(ComboBox2.SelectedItem, clsComboBoxItem)
MessageBox.Show("Item Text=" & itmCombo.ItemText & " and ItemIndex=" & CStr(itmCombo.ItemIndex))
End If
Can anyone tell help me to understand how get an element by his index stored in the class? Eg writing '2' into a text box, the combo box sould be show "sometext2".
Suppose i want to expand the class adding some values, like m_ItemText2,m_ItemText3 etc, i would learn a method to get all of theese values.
I hope I was clear
Thanks in advance
If you have a DataSource set to a DataTable for your ComboBox, just set the DisplayMember and ValueMember. My test ComboBox is set to DropDownList.
Private Sub FillComboBox()
Dim dt As New DataTable
Using con As New SqlConnection(ConStr),
cmd As New SqlCommand("Select FlavorID,FlavorName From Flavors", con)
con.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
ComboBox1.DisplayMember = "FlavorName"
ComboBox1.ValueMember = "FlavorID"
ComboBox1.DataSource = dt
End Sub
To display the the values
To display the Text cast to DataRowView (that is the object that is in the Item), provide the field you want and call ToString.
Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox1.SelectionChangeCommitted
MessageBox.Show(ComboBox1.SelectedValue.ToString)
MessageBox.Show(DirectCast(ComboBox1.SelectedItem, DataRowView)("FlavorName").ToString)
End Sub
If you are adding items one by one, you can still set the DisplayMember and ValueMember.
'https://stackoverflow.com/questions/38206678/set-displaymember-and-valuemember-on-combobox-without-datasource
Private Sub SomeFormsLoadEvent()
ComboBox1.Items.Add(New KeyValuePair(Of String, Integer)("Ultra-fast", 600))
ComboBox1.Items.Add(New KeyValuePair(Of String, Integer)("Fast", 300))
ComboBox1.Items.Add(New KeyValuePair(Of String, Integer)("Medium", 150))
ComboBox1.Items.Add(New KeyValuePair(Of String, Integer)("Slow", 75))
ComboBox1.DisplayMember = "Key"
ComboBox1.ValueMember = "Value"
ComboBox1.DataSource = ComboBox1.Items
End Sub
I found it a bit more complicated to display the text. I had to cast the item to its underlying type (KeyValuePair) then ask for the Key value.
Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox1.SelectionChangeCommitted
MessageBox.Show(ComboBox1.SelectedValue.ToString)
MessageBox.Show(DirectCast(ComboBox1.SelectedItem, KeyValuePair(Of String, Integer)).Key)
End Sub
As I understand it you want to store values in a class and display and access them through the combobox. How about this approach:
The class for the values:
Public Class clsValues
Private lstItemTexts As New List(Of String)
Public ReadOnly Property AllValues As List(Of String)
Get
Return lstItemTexts
End Get
End Property
'To initialize class with empty list, items can be added with AddItems
Public Sub New()
End Sub
'To initialize class with items, items can still be added with AddItems
Public Sub New(lstItemTexts As List(Of String))
Me.lstItemTexts = lstItemTexts
End Sub
Public Sub AddItem(item As String)
Me.lstItemTexts.Add(item)
End Sub
Public Function GetItemByIndex(index As Integer) As String
Return lstItemTexts(index)
End Function
Public Function GetIndexByItem(item As String) As Integer
Return lstItemTexts.IndexOf(item)
End Function
End Class
You can declare it and fill values like this:
Private Values As New clsValues()
Values.AddItem("Some Text 1")
Values.AddItem("Some Text 2")
or
Private Values As New clsValues(New List(Of String)({"Some Text 1", "Some Text 2"}))
to get a value from combobox
Private Sub ComboBox2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox2.SelectedIndexChanged
MessageBox.Show(Values.GetItemByIndex(ComboBox2.SelectedIndex))
End Sub
What #Mary stated is true the ComboBox has values that are useful SEE CODE BELOW
Change gvTxType to be a TextBox to see results when you click on the tvTxType
Private Sub cbTxType_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbTxType.SelectedIndexChanged
If cbTxType.SelectedIndex > -1 Then
'Dim sindex As Integer
'sindex = cbTxType.SelectedIndex
'Dim sitem As String
sitem = CType(cbTxType.SelectedItem, String)
'MsgBox("You Selected " & sitem)
'Index is ZERO based
gvTxType = sitem
End If
End Sub

How to check elements from an array in a CheckListBox

i have a checklisbox with some value, let's say
"Apple"
"Peach"
"Lemon"
These values came from a dataset.
I have an array with Apple and Lemon: {"Apple", "Lemon"}.
How to check in the checklistbox each value read in this array?
EDIT: In my case, the checklistbox was populate using a dataset provided by a SQL query
In the following code sample, data from SQL-Server (database doesn't matter but this is what I used, what is important is the container the data is loaded into is loaded into a list.
Container to hold data
Public Class Category
Public Property Id() As Integer
Public Property Name() As String
Public Overrides Function ToString() As String
Return Name
End Function
End Class
Class to read data
Imports System.Data.SqlClient
Public Class SqlOperations
Private Shared ConnectionString As String =
"Data Source=.\SQLEXPRESS;Initial Catalog=NorthWind2020;Integrated Security=True"
Public Shared Function Categories() As List(Of Category)
Dim categoriesList = New List(Of Category)
Dim selectStatement = "SELECT CategoryID, CategoryName FROM Categories;"
Using cn As New SqlConnection With {.ConnectionString = ConnectionString}
Using cmd As New SqlCommand With {.Connection = cn}
cmd.CommandText = selectStatement
cn.Open()
Dim reader = cmd.ExecuteReader()
While reader.Read()
categoriesList.Add(New Category() With {.Id = reader.GetInt32(0), .Name = reader.GetString(1)})
End While
End Using
End Using
Return categoriesList
End Function
End Class
Extension method
Which can check or uncheck a value if found in the CheckedListBox and is case insensitive.
Public Module Extensions
<Runtime.CompilerServices.Extension>
Public Function SetCategory(sender As CheckedListBox, text As String, Optional checkedValue As Boolean = True) As Boolean
If String.IsNullOrWhiteSpace(text) Then
Return False
End If
Dim result = CType(sender.DataSource, List(Of Category)).
Select(Function(item, index) New With
{
Key .Column = item,
Key .Index = index
}).FirstOrDefault(Function(this) _
String.Equals(this.Column.Name, text, StringComparison.OrdinalIgnoreCase))
If result IsNot Nothing Then
sender.SetItemChecked(result.Index, checkedValue)
Return True
Else
Return False
End If
End Function
End Module
Form code
Public Class ExampleForm
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CheckedListBox1.DataSource = SqlOperations.Categories
End Sub
Private Sub CheckCategoryButton_Click(sender As Object, e As EventArgs) Handles CheckCategoryButton.Click
CheckedListBox1.SetCategory(CategoryToCheckTextBox.Text, StateCheckBox.Checked)
End Sub
End Class
To check all at once
Private Sub CheckAllButton_Click(sender As Object, e As EventArgs) Handles CheckAllButton.Click
CType(CheckedListBox1.DataSource, List(Of Category)).
ForEach(Sub(cat) CheckedListBox1.SetCategory(cat.Name, True))
End Sub
You haven't mentioned exactly how the CheckedListBox gets populated by the DataSet, I've made the assumption that you add Strings directly to the Items collection.
This code will simply loop through the CheckedListBox and compare the values with the array, whatever the match result, the Checkbox is either ticked or cleared.
Dim theArray() As String = {"Apple", "Lemon"}
For counter As Integer = 0 To CheckedListBox1.Items.Count - 1
Dim currentItem As String = CheckedListBox1.Items(counter).ToString
Dim match As Boolean = theArray.Contains(currentItem.ToString)
CheckedListBox1.SetItemChecked(counter, match)
Next
Use the SetItemChecked method like this:
CheckedListBox1.SetItemChecked(CheckedListBox1.Items.IndexOf("your item goes here"), True)
Note that if the item does not exist, an exception will be thrown, so be sure to check for the item before calling the SetItemChecked() method. To do that, you can check for the return value of IndexOf(). It will be -1 if the item does not exist.

Passing list to function as parameter

I have a function that will perform work on a list, but I cannot get it to accept more than one datatype. For example:
Public Sub PopulateListBox (objectList as List(of VariantType), ListboxToPopulate as Listbox)
listboxToPopulate.Items.Clear() 'clears the items in the listbox
For Each item In objectList
listboxToPopulate.Items.Add(item.ToString)
Next
End
The problem is that I have lists of different classes, like employee, building address, etc. I cannot pass a List(Of EmployeeClass) because it says it cannot be converted to List(Of VariantType). I have also tried List(Of Object) and the same result.
I will demonstrate the use by first showing you a sample class.
Public Class Coffee
Public Property ID As Integer
Public Property Name As String
Public Property Type As String
Public Sub New(iid As Integer, sname As String, stype As String)
ID = iid
Name = sname
Type = stype
End Sub
Public Overrides Function ToString() As String
Return Name
End Function
End Class
I added a parameterized constructor just to make it easy to get a fully populate Coffee. You need to add the .ToString override so the list box will know what to display.
Here is where my List(Of Coffee) comes from.
Private Function FillCoffeeList() As List(Of Coffee)
Dim CoffeeList As New List(Of Coffee)
Using cn As New SqlConnection(My.Settings.CoffeeConnection),
cmd As New SqlCommand("Select Top 10 ID, Name, Type From Coffees;", cn)
cn.Open()
Using reader = cmd.ExecuteReader
Do While reader.Read
Dim c As New Coffee(reader.GetInt32(0), reader.GetString(1), reader.GetString(2))
CoffeeList.Add(c)
Loop
End Using
End Using
Return CoffeeList
End Function
As commented by Hans Passant, change the datatype of objectList to IEnumerable(Of Object).
Public Sub PopulateListBox(objectList As IEnumerable(Of Object), ListboxToPopulate As ListBox)
ListboxToPopulate.Items.Clear() 'clears the items in the listbox
For Each item In objectList
ListboxToPopulate.Items.Add(item)
Next
End Sub
Now I can pass a List(Of Coffee) to the PopulateListBox method.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim CList = FillCoffeeList()
PopulateListBox(CList, ListBox1)
End Sub
I can access the properties of the underlying type be casting.
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
Dim t = ListBox1.SelectedItem.GetType
Select Case t.Name
Case "Coffee"
Dim c = DirectCast(ListBox1.SelectedItem, Coffee)
TextBox1.Text = c.ID.ToString
TextBox2.Text = c.Type
End Select
End Sub
You can add additionsl cases depending on what types you are expecting. There is probably a better way to do this.

Modify a structure field containing combobox when SelectedIndex event fires

I am trying to have a generic widget composed of a label and a value. The value is set by a combobox. Here is the structure:
Structure tParam
Dim label As Label
Dim comboBox As ComboBox
Dim valueX As String
End Structure
Dim parameter1 As tParam
I'd like to modify the valueX as the SelectedIndexChanged event is fired.
For now I have set
parameter1.label.text = "Id"
parameter1.comboBox.Tag = parameter1 ' the struct itself
AddHandler parameter1.comboBox.SelectedIndexChanged, AddressOf updateParam
and in the handler
Private Sub updateParam(sender As Object, e As System.EventArgs)
Dim parameterX As tParam = sender.Tag
With parameterX
Select Case .label.Text
Case "Id"
parameter1.valueX = .comboBox.SelectedIndex
End Select
End Sub
The problem is that I have a lot (>50) parameters of type tParam and I like not to check every parameter name with the select case.
Note that I am calling directly parameter1 in the handler, because parameterX (=sender.Tag) is read-only, as any update to parameterX is local.
I cant quite tell what you are trying to do, but tStruct.ComboBox.Tag = Me seems a convoluted way to track your widgets. Using a class, you could internalize and simplify some of what it seems you are trying to do:
Public Class CBOWidgetItem
Private WithEvents myCBO As ComboBox
Private myLbl As Label
Public Property Name As String
Public Property Value As String
Public Sub New(n As String, cbo As ComboBox, lbl As Label)
Name = n
myCBO = cbo
myLbl = lbl
End Sub
Private Sub myCBO_SelectedIndexChanged(sender As Object,
e As EventArgs) Handles myCBO.SelectedIndexChanged
Value = myCBO.SelectedIndex.ToString
End Sub
Public Overrides Function ToString() As String
Return Name
End Function
End Class
The widget is able to handle the Value change itself (again, I dont quite know what you are up to). You might have other wrapper props to expose certain info the widget is managing:
Public ReadOnly Property LabelText As String
Get
If myLbl IsNot Nothing Then
Return myLbl.Text
Else
Return ""
End If
End Get
End Property
To use it:
' something to store them in:
Private widgets As List(Of CBOWidgetItem)
...
widgets = New List(Of CBOWidgetItem)
' long form
Dim temp As New CBOWidgetItem("ID", ComboBox1, Label1)
widgets.Add(temp)
' short form:
widgets.Add(New CBOWidgetItem("foo", ComboBox2, Label2))
Elsewhere if you need to find one of these guys:
Dim find = "ID"
Dim specificItem = widgets.Where(Function(s) s.Name = find).FirstOrDefault
If specificItem IsNot Nothing Then
Console.WriteLine(specificItem.Name)
End If
Alternatively, you could use a Dictionary(Of String, CBOWidgetItem) and get them back by name.

sort results (find method) not working

I am using ArcGIS. I am trying to sort the data manually after its found. I created a property class and loop through a Tlist to scrub unwanted data. However right before it binds to the data grid, I receive a cast error. I assume something is coming back null. Am I missing something??
Public Class temp
Public Sub New()
End Sub
Public Property DisplayFieldName As String
Public Property Feature As ESRI.ArcGIS.Client.Graphic
Public Property FoundFieldName As String
Public Property LayerId As Integer
Public Property LayerName As String
Public Property Value As Object
End Class
Public Class templst
Public Sub New()
Dim findresult = New List(Of temp)
End Sub
Private _findresult = findresult
Public Property findresult() As List(Of temp)
Get
Return _findresult
End Get
Set(ByVal value As List(Of temp))
_findresult = value
End Set
End Property
End Class
Private Sub FindTask_Complete(ByVal sender As Object, ByVal args As FindEventArgs)
Dim newargs As New templst() 'puts Tlist (temp) into property
Dim templistNUMONLY As New List(Of temp) 'Tlist of temp
For Each r In args.FindResults 'class in compiled dll.
If Regex.Match(r.Value.ToString, "[0-9]").Success Then
templistNUMONLY.Add(New temp() With {.LayerId = r.LayerId,
.LayerName = r.LayerName,
.Value = r.Value,
.FoundFieldName = r.FoundFieldName,
.DisplayFieldName = r.DisplayFieldName,
.Feature = r.Feature})
End If
Next
newargs.findresult = templistNUMONLY
Dim sortableView As New PagedCollectionView(newargs.findresult)
FindDetailsDataGrid.ItemsSource = sortableView 'populate lists here
End Sub
BIND TO GRID HERE: (Error here)
Private Sub FindDetails_SelectionChanged(ByVal sender As Object, ByVal e As SelectionChangedEventArgs)
' Highlight the graphic feature associated with the selected row
Dim dataGrid As DataGrid = TryCast(sender, DataGrid)
Dim selectedIndex As Integer = dataGrid.SelectedIndex
If selectedIndex > -1 Then
'''''''''''''''''CAST ERROR HERE:
Dim findResult As FindResult = CType(FindDetailsDataGrid.SelectedItem, FindResult)
You populate FindDetailsDataGrid with objects of type temp, but you try to cast it to type FindResult instead. You should do:
Dim selectedTemp As temp = CType(FindDetailsDataGrid.SelectedItem, temp)
'*Create find result from selected temp object here*