Receive and control serial device data in visual basic - vb.net

I have a serial device which sends me data at the baudrate of 38400 and i get it like this ?#D00014C000 000. I can see data comes in on a ritchtextbox but what im trying to do is to use some characters from the string in a list box.
For example i want characters "14C" appears in the listbox3. I tried the substring and mid function but listbox lidnt work properly and losses characters or confuse them . Here is my code. Any suggestions please??
Imports System
Imports System.ComponentModel
Imports System.Threading
Imports System.IO.Ports
Public Class frmMain
Dim myPort As Array
Delegate Sub SetTextCallback(ByVal [text] As String)
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
ReceivedText(SerialPort1.ReadExisting())
End Sub
Private Sub ReceivedText(ByVal [text] As String)
If Me.rtbReceived.InvokeRequired Then
Dim x As New SetTextCallback(AddressOf ReceivedText)
Me.Invoke(x, New Object() {(text)})
Else
Me.rtbReceived.Text &= [text]
Dim fine As String = Mid([text], 7, 3)
Dim list As Integer = ListBox3.Items.Add(fine)
End If
End Sub
End Class
Here isPICTURE 1 what happens
Picture2

Related

see what is attached to a com port and show in combo box

Using the code below I can create a box with a combo box that shows the current com ports
What I need to do is show what is attached to the com Port, for example I want it to list
COM PORT1 FTDI USB serial adapter, the reason is to let you the user know which port to enter in a batch file that runs when another button is clicked ( i have removed that part of the code as its not important)
I have done some google work and found this link http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/331a26c1-0f42-4cf1-8adb-32fb09a18953/ But that just errors out
Imports System
Imports System.Threading
Imports System.IO.Ports
Imports System.ComponentModel
Public Class Form1
'------------------------------------------------
Dim myPort As Array
Delegate Sub SetTextCallback(ByVal [text] As String) 'Added to prevent threading
errors during receiveing of data
'------------------------------------------------
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
myPort = IO.Ports.SerialPort.GetPortNames()
ComboBox1.Items.AddRange(myPort)
End Sub
End Class
The following shows how to get a list of COM devices in VB.NET for both .NET 6 and .NET Framework 4.8 in VS 2022. If a USB COM (serial port) device is added/removed, the ComboBox will be updated.
Option 1 - Windows Forms App: (.NET 6)
Create a new project: Windows Forms App (name: SerialPortGetComDevices)
Download/install the following NuGet packages:
System.IO.Ports
System.Management
Option 2 - Windows Forms App (.NET Framework) - v4.8:
Create a new project: Windows Forms App (.NET Framework) (name: SerialPortGetComDevices)
Add Reference:
In VS menu, click Project
Select Add Reference...
Select Assemblies
Check System.Management
Click OK
The instructions below are the same for both Windows Forms App and Windows Forms App (.NET Framework) (ie: the instructions below are the same regardless of which option you've chosen above).
Create a class (name: ComPortInfo.vb)
In VS menu, select Project
Select Add Class... (name: ComPortInfo.vb)
Click Add
ComPortInfo.vb:
Public Class ComPortInfo
Public Property Caption As String
Public Property PortName As String
End Class
Open Solution Explorer:
In VS menu, click View
Select Solution Explorer
Open Properties Window:
In VS menu, click View
Select Properties Window
Add Load Event Handler
In Solution Explorer, right-click Form1.vb and select View Designer.
In Properties Window, click
Double-click Load
Add FormClosing Event Handler
In Solution Explorer, right-click Form1.vb and select View Designer.
In Properties Window, click
Double-click FormClosing
Add a ComboBox to the Form (name: ComboBoxComPorts)
In VS menu, click View
Select Toolbox
In Toolbox, select ComboBox, and drag it to the Form.
In the Properties Window, change (Name) to ComboBoxComPorts
In the Properties Window, change DropDownStyle to DropDownList
Select one of the options below. The 1st option uses ManagementEventWatcher to detect USB device insertion and removal. The 2nd option overrides WndProc.
Note: The WndProc version (Option 2) seems to have slightly better performance.
Option 1 (ManagementEventWatcher)
Note: The code for detecting the insertion and removal of a USB device, is adapted from here.
Add the code below in your Form (ex: Form1.vb)
Form1.vb
Imports System.ComponentModel
Imports System.Management
Imports System.IO.Ports
Public Class Form1
'create new instance
Private _comPorts As BindingList(Of ComPortInfo) = New BindingList(Of ComPortInfo)
Private _managementEventWatcher1 As ManagementEventWatcher = New ManagementEventWatcher()
Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitializeManagementEventWatcher()
UpdateCOM()
'set properties
ComboBoxComPorts.DataSource = _comPorts
ComboBoxComPorts.DisplayMember = "Caption"
ComboBoxComPorts.ValueMember = "PortName"
End Sub
Private Sub GetComPorts()
'this method Is only called from 'UpdateCOM'
'_comPorts' is only modified in this method
Dim portDict As Dictionary(Of String, String) = New Dictionary(Of String, String)
'clear existing data
_comPorts.Clear()
'get port names
For Each pName As String In SerialPort.GetPortNames()
If Not portDict.ContainsKey(pName) Then
portDict.Add(pName, pName) 'add to Dictionary
End If
Next
'get USB COM ports - this may result in a more descriptive name than 'COM1'
Using searcherPnPEntity As ManagementObjectSearcher = New ManagementObjectSearcher("SELECT Name FROM Win32_PnPEntity WHERE PNPClass = 'Ports'")
For Each objPnPEntity As ManagementObject In searcherPnPEntity.Get()
If objPnPEntity Is Nothing Then
Continue For
End If
'get name
Dim name As String = objPnPEntity("Name")?.ToString()
If Not String.IsNullOrEmpty(name) AndAlso name.ToUpper().Contains("COM") Then
Dim portName As String = name.Substring(name.IndexOf("(") + 1, name.IndexOf(")") - name.IndexOf("(") - 1)
If Not portDict.ContainsKey(portName) Then
portDict.Add(portName, name) 'add to Dictionary
Else
portDict(portName) = name 'update value
End If
End If
Next
End Using
'add items from Dictionary to BindingList
For Each kvp As KeyValuePair(Of String, String) In portDict
_comPorts.Add(New ComPortInfo() With {.Caption = kvp.Value, .PortName = kvp.Key}) 'add
Next
End Sub
Private Sub InitializeManagementEventWatcher()
'see https:'learn.microsoft.com/en-us/windows/win32/wmisdk/within-clause
'WITHIN sets the polling interval in seconds
'polling too frequently may reduce performance
Dim query As WqlEventQuery = New WqlEventQuery("SELECT * FROM __InstanceOperationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_PnPEntity'")
'Dim query As WqlEventQuery = New WqlEventQuery("SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_PnPEntity'")
'set property
_managementEventWatcher1.Query = query
'subscribe to event
AddHandler _managementEventWatcher1.EventArrived, AddressOf ManagementEventWatcher_EventArrived
'start
_managementEventWatcher1.Start()
End Sub
Private Sub LogMsg(msg As String, Optional includeTimestamp As Boolean = True)
If includeTimestamp Then
msg = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff")} - {msg}"
End If
Debug.WriteLine(msg)
End Sub
Public Sub UpdateCOM()
If ComboBoxComPorts.InvokeRequired Then
'LogMsg("ComboBoxComPorts.InvokeRequired")
ComboBoxComPorts.Invoke(New MethodInvoker(Sub()
GetComPorts()
End Sub))
Else
GetComPorts()
End If
End Sub
Public Sub ManagementEventWatcher_EventArrived(sender As Object, e As EventArrivedEventArgs)
Dim obj As ManagementBaseObject = DirectCast(e.NewEvent, ManagementBaseObject)
Dim target As ManagementBaseObject = If(obj("TargetInstance") IsNot Nothing, DirectCast(obj("TargetInstance"), ManagementBaseObject), Nothing)
Dim usbEventType As String = String.Empty
Select Case target.ClassPath.ClassName
Case "__InstanceCreationEvent"
usbEventType = "added"
Case "__InstanceDeletionEvent"
usbEventType = "removed"
Case Else
usbEventType = target.ClassPath.ClassName
End Select
If target("PNPClass") IsNot Nothing AndAlso target("PNPClass").ToString() = "Ports" Then
'update COM ports
UpdateCOM()
End If
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
'stop
_managementEventWatcher1.Stop()
'unsubscribe from event
RemoveHandler _managementEventWatcher1.EventArrived, AddressOf ManagementEventWatcher_EventArrived
End Sub
End Class
Option 2 (override WndProc)
Note: The code for detecting the insertion and removal of a USB device, is adapted from here.
Add a Module (name: UsbDeviceNotification.vb)
In VS menu, select Project
Select Add Module... (name: UsbDeviceNotification.vb)
Click Add
UsbDeviceNotification.vb
Imports System.Runtime.InteropServices
Module UsbDeviceNotification
Public Const DbtDeviceArrival As Integer = &H8000 'device added
Public Const DbtDeviceRemoveComplete As Integer = &H8004 'device removed
Public Const WM_DEVICECHANGE As Integer = &H219 'device change event
Public Const DBT_DEVTYP_DEVICEINTERFACE As Integer = 5
Private ReadOnly _guidDevInterfaceUSBDevice As Guid = New Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED") 'USB devices
Private _notificationHandle As IntPtr
Declare Auto Function RegisterDeviceNotification Lib "user32" (recipient As IntPtr, notificationFilter As IntPtr, flags As Integer) As IntPtr
Declare Auto Function UnregisterDeviceNotification Lib "user32" (hwnd As IntPtr) As Boolean
<StructLayout(LayoutKind.Sequential)>
Private Structure DEV_BROADCAST_DEVICEINTERFACE
Dim Size As Integer
Dim DeviceType As Integer
Dim Reserved As Integer
Dim ClassGuid As Guid
Dim Name As Short
End Structure
Public Sub RegisterUsbDeviceNotification(hwnd As IntPtr)
'Registers a window to receive notifications when USB devices are plugged or unplugged.
Dim dbi As DEV_BROADCAST_DEVICEINTERFACE = New DEV_BROADCAST_DEVICEINTERFACE() With
{
.DeviceType = DBT_DEVTYP_DEVICEINTERFACE,
.ClassGuid = _guidDevInterfaceUSBDevice
}
dbi.Size = Marshal.SizeOf(dbi)
Dim buffer As IntPtr = Marshal.AllocHGlobal(dbi.Size)
Marshal.StructureToPtr(dbi, buffer, True)
_notificationHandle = RegisterDeviceNotification(hwnd, buffer, 0)
End Sub
Public Sub UnregisterUsbDeviceNotification()
UnregisterDeviceNotification(_notificationHandle)
End Sub
End Module
Add the code below in your Form (ex: Form1.vb)
Form1.vb
Imports System.ComponentModel
Imports System.Management
Imports System.IO.Ports
Imports System.Threading
Public Class Form1
'create new instance
Private _comPorts As BindingList(Of ComPortInfo) = New BindingList(Of ComPortInfo)
Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
UpdateCOM()
'set properties
ComboBoxComPorts.DataSource = _comPorts
ComboBoxComPorts.DisplayMember = "Caption"
ComboBoxComPorts.ValueMember = "PortName"
End Sub
Private Sub GetComPorts()
'this method Is only called from 'UpdateCOM'
'_comPorts' is only modified in this method
Dim portDict As Dictionary(Of String, String) = New Dictionary(Of String, String)
'clear existing data
_comPorts.Clear()
'get port names
For Each pName As String In SerialPort.GetPortNames()
If Not portDict.ContainsKey(pName) Then
portDict.Add(pName, pName) 'add to Dictionary
End If
Next
'get USB COM ports - this may result in a more descriptive name than 'COM1'
Using searcherPnPEntity As ManagementObjectSearcher = New ManagementObjectSearcher("SELECT Name FROM Win32_PnPEntity WHERE PNPClass = 'Ports'")
If searcherPnPEntity IsNot Nothing Then
For Each objPnPEntity As ManagementBaseObject In searcherPnPEntity.Get()
If objPnPEntity Is Nothing Then
Continue For
End If
'get name
Dim name As String = objPnPEntity("Name")?.ToString()
If Not String.IsNullOrEmpty(name) AndAlso name.ToUpper().Contains("COM") Then
Dim portName As String = name.Substring(name.IndexOf("(") + 1, name.IndexOf(")") - name.IndexOf("(") - 1)
If Not portDict.ContainsKey(portName) Then
portDict.Add(portName, name) 'add to Dictionary
Else
portDict(portName) = name 'update value
End If
End If
Next
End If
End Using
'add items from Dictionary to BindingList
For Each kvp As KeyValuePair(Of String, String) In portDict
_comPorts.Add(New ComPortInfo() With {.Caption = kvp.Value, .PortName = kvp.Key}) 'add
Next
End Sub
Private Sub LogMsg(msg As String, Optional includeTimestamp As Boolean = True)
If includeTimestamp Then
msg = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff")} - {msg}"
End If
Debug.WriteLine(msg)
End Sub
Public Sub UpdateCOM()
'since this method/Sub is called from WndProc,
'it needs to run on a new thread
Dim threadProc As System.Threading.Thread = New System.Threading.Thread(Sub()
If ComboBoxComPorts.InvokeRequired Then
'LogMsg("ComboBoxComPorts.InvokeRequired")
ComboBoxComPorts.Invoke(New MethodInvoker(Sub()
GetComPorts()
End Sub))
Else
GetComPorts()
End If
End Sub)
threadProc.SetApartmentState(System.Threading.ApartmentState.STA)
threadProc.Start()
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = UsbDeviceNotification.WM_DEVICECHANGE Then
Select Case CInt(m.WParam)
Case UsbDeviceNotification.DbtDeviceRemoveComplete
UpdateCOM()
Case UsbDeviceNotification.DbtDeviceArrival
UpdateCOM()
End Select
End If
MyBase.WndProc(m)
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
End Sub
End Class
The following PowerShell commands may also provide useful information.
PowerShell:
Get-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_SerialPort Where Name like '%COM%'"
Get-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_SerialPortConfiguration"
Get-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_PnPEntity where PnPClass = 'Ports' and Name like '%COM%'"
mode
Resources:
System.IO.Ports Namespace
SerialPort Class
BindingList Class
ManagementEventWatcher Class
WITHIN Clause
Detecting USB drive insertion and removal using windows service and c#
Check for device change (add/remove) events
ComboBox Class
Dictionary<TKey,TValue> Class
ManagementObjectSearcher Class
ManagementObject Class
Win32_PnPEntity class
For...Next Statement (Visual Basic)
If Operator (Visual Basic)

VB.Net Dictionary inside of a dictionary adding / removing data

I'm creating an application where I have different libraries, books and non-book media stored in dictionaries and displayed in listboxes. The user can add and remove additional dictionaries for any of these 3 elements. My issue lies in bringing up the new form to create a link between a library and it's media.
I have a listbox for "Books at Current library" and "Non-Book Media at Current Library" Which will display the media that is linked to the specific library that is highlighted in the listbox. And the user can freely add and remove different media to the library.
frmManager: https://prnt.sc/mnd8qf
frmAssociationScreen: https://prnt.sc/mnd8sh
I'm trying to create a dictionary within a dictionary that I can manipulate the data with for adding the different media to the individual libraries. But I'm unsure where to go from here, I'd like to start by hard coding a few links to Zahnow Library and add a few books as well as one non-book media.
Public Class frmManager
' Global data structures
Public Libraries As New Dictionary(Of String, String)
Public Books As New Dictionary(Of String, String)
Public nonBookMedia As New Dictionary(Of String, String)
Public EquippedLibrary As New Dictionary(Of String, LibraryWithMedia)
Structure LibraryWithMedia
Dim strLibraryName As String
Dim dicBooks As Dictionary(Of String, String)
Dim nonBookMedia As Dictionary(Of String, String)
End Structure
Private Sub frmManager_Load(sender As Object, e As EventArgs) Handles Me.Load
Libraries.Add("SVSU", "Zahnow Library")
Libraries.Add("BR", "Fleschner Memorial Library")
Libraries.Add("SDJ", "Scott D. James Technical Repository")
Books.Add("104", "Data Structures for Fun and Profit")
Books.Add("103", "Doing More With Less - Naval Lint Art")
Books.Add("102", "Interpretive Klingon Poetry")
Books.Add("105", "Programming with the Bidgoli")
Books.Add("101", "Zen and the Art of Appliance Wiring")
nonBookMedia.Add("201", "CD - IEEE Computer: the Hits")
nonBookMedia.Add("203", "DVD - Databases and You: the Video Experience")
nonBookMedia.Add("202", "DVD - The Pirates of Silicon Valley")
populatelstLibrary()
populatelstBooks()
populatelstBookMedia()
End Sub
Sub populatelstLibrary()
lstLibraries.Items.Clear()
For Each library In Libraries
lstLibraries.Items.Add(library.Value & " --- " & library.Key)
Next
End Sub
How I manipulated the data to delete library dictionary
Private Sub btnDeleteLibrary_Click(sender As Object, e As EventArgs) Handles btnDeleteLibrary.Click
Dim key As String = ""
Dim tmpLibraries As New Dictionary(Of String, String)
' If an index is selected in listbox then continue
' If nothing selected, the button does nothing
If lstLibraries.SelectedIndex > -1 Then
If MsgBox("Are you sure you want to delete this library?", MsgBoxStyle.YesNoCancel, "Delete confirmation") = MsgBoxResult.Yes Then
For Each library In Libraries
If lstLibraries.SelectedItem.Equals(library.Value & " --- " & library.Key) Then
' DoNothing
' the selected item is not added to temp library
Else
' Add all other values to temp library
tmpLibraries.Add(library.Key, library.Value)
End If
Next
lstLibraries.Items.Clear() ' Clear the list box
Libraries = tmpLibraries ' Set dictionary Libraries equal to temp libararies
tmpLibraries = Nothing ' Set temp library back to nothing
populatelstLibrary() ' Repopulate the list box
End If
End If
End Sub
frmAssociationScreen.vb
Public Class frmAssociationScreen
Private Sub frmAssociationScreen_Load(sender As Object, e As EventArgs) Handles Me.Load
lstAllLibraries.Items.Clear()
For Each library In frmManager.Libraries
lstAllLibraries.Items.Add(library.Value & " --- " & library.Key)
Next
For Each book In frmManager.Books
lstAllBooks.Items.Add(book.Value & " --- " & book.Key)
Next
For Each nonBook In frmManager.nonBookMedia
lstAllMedia.Items.Add(nonBook.Value & " --- " & nonBook.Key)
Next
End Sub
Private Sub btnManagerScreen_Click(sender As Object, e As EventArgs) Handles btnManagerScreen.Click
Me.Close() ' Close current form
frmManager.Visible = True ' Make manager form visible
End Sub
Private Sub btnAddBook_Click(sender As Object, e As EventArgs) Handles btnAddBook.Click
End Sub
Private Sub btnRemoveBook_Click(sender As Object, e As EventArgs) Handles btnRemoveBook.Click
End Sub
Private Sub lstAllLibraries_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstAllLibraries.SelectedIndexChanged
End Sub
End Class
Some slight changes in your code as below:
In your structure LibraryWithMedia
We added SUB NEW
' Structure of single library
Structure LibraryWithMedia
'
Dim strLibraryName As String
Dim dicBooks As Dictionary(Of String, String)
Dim nonBookMedia As Dictionary(Of String, String)
'
'new library constructor
Sub New(ByVal LibName As String)
strLibraryName = LibName
dicBooks = New Dictionary(Of String, String)
nonBookMedia = New Dictionary(Of String, String)
End Sub
'
End Structure
In your EquippedLibrary declaration.
The declaration changed from (string, string) to simply LibraryWithMedia
Public EquippedLibrary As List(Of LibraryWithMedia)
At the end/bottom of your Form_Load event
' construct equipped library and define the library names
EquippedLibrary = New List(Of LibraryWithMedia)
' initialise each library with empty books/media dictionaries
populateEquippedLibNames
The PopulateEquippedLibNames Subroutines (this is a new subroutine)
Sub populateEquippedLibNames()
'
Dim Counta As Integer
Dim tmpSingleLib As LibraryWithMedia
'
For Counta = 0 To Libraries.Count - 1
tmpSingleLib = New LibraryWithMedia(Libraries.Values(Counta))
EquippedLibrary.Add(tmpSingleLib)
tmpSingleLib = Nothing
Next
'
End Sub
And then for adding/removing each book to the SELECTED library in the TOP listbox
Private Sub btnAddBook_Click(sender As Object, e As EventArgs) Handles btnAddBook.Click
'
EquippedLibrary(lstLibraries.SelectedIndex).dicBooks.Add(Books.Keys(lstBooks.SelectedIndex), Books.Values(lstBooks.SelectedIndex))
lstSelectedBooks.Items.Add(lstBooks.SelectedItem)
'
End Sub
Private Sub btnRemoveBook_Click(sender As Object, e As EventArgs) Handles btnRemoveBook.Click
'
EquippedLibrary(lstLibraries.SelectedIndex).dicBooks.Remove(Books.Keys(lstBooks.SelectedIndex))
'
End Sub
Note that to add a book/media to a library,
A library MUST BE selected in the TOP listbox
The Book or Media being added must also be selected
No error checking is performed, so you will need to add it (such as a listbox has a selection or not) etc
Update
I have added the libraries on change code for you below
Private Sub lstLibraries_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstLibraries.SelectedIndexChanged
'
Dim Counta As Integer
'
lstSelectedBooks.Items.Clear()
lstSelectedMedia.Items.Clear()
If EquippedLibrary(lstLibraries.SelectedIndex).dicBooks.Count > 0 Then
For Counta = 0 To EquippedLibrary(lstLibraries.SelectedIndex).dicBooks.Count - 1
lstSelectedBooks.Items.Add(EquippedLibrary(lstLibraries.SelectedIndex).dicBooks.Keys(Counta) & " --- " & EquippedLibrary(lstLibraries.SelectedIndex).dicBooks.Values(Counta))
Next
End If
Counta = Nothing
'
End Sub

Own class can't convert string to integer

https://imgur.com/a/gaXh4
Ok so I have a problem a really weird problem. So I created a new class which is a new type of TextBox. It keeps track of the objects created from it with the help of a list but. This all works, with for each I can get all objects of the class but when I want to convert the string from the TextBox into a integer I can't do it because it thinks its not convertable eventhought the string only consists out of number symbols
Code for Button
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'TextBox1.Text = CInt(SumTextBox1.Text) + CInt(SumTextBox2.Text)
For Each item As SumTextBox In SumTextBox.sumList
Dim textItem As SumTextBox = item
TextBox1.Text = CInt(TextBox1.Text) + CInt(textItem.Text)
Next
End Sub
Public Class SumTextBox
Inherits TextBox
Public Shared sumList As New List(Of SumTextBox)
Sub New()
Size = New Size(90, 10)
sumList.Add(Me)
End Sub
End Class
Try using Convert.toInt32(TextBox1.Text) and the same for textitem.text

update listbox in GUI from other classes

I have a listbox on my main vb.net form which I am using to display status messages from the server program I am running. My actual program consists of many different classes (in separate files) and what I would like to be able to do is to call the Sub frm.UpdateList("With Info in Here") from each of the classes to write to the listbox.
If I call the frm.UpdateList or UpdateList from the frm class, it writes to the listbox fine, but if I call it from any other class nothing happens (I don't get an error either).
I have tried with and without making it shared (and changing frm to me) but neither works as I would hope.
Would anyone be able to help me understand why this is not working, I have invoked the item, and it does get added to but just not from a separate class (which is what I need it to do).
Many Thanks!
Private Delegate Sub UpdateListDelegate(ByVal itemName As String)
Public Shared Sub UpdateList(ByVal itemName As String)
If frm.InvokeRequired Then
frm.Invoke(New UpdateListDelegate(AddressOf UpdateList), itemName)
Else
frm.ListBox1.Items.Insert(0, DateTime.Now.ToString & ": " & itemName)
End If
End Sub
Edit: Try 2, with the following thanks to Idle_Mind works on the frm class (frm is the main form and only form) but it still does not write to the listbox when called from other classes (and no errors occur):
Public Shared Sub UpdateList(ByVal itemName As String)
Dim frm As Form = My.Application.ApplicationContext.MainForm
If Not IsNothing(frm) Then
Dim matches() As Control = frm.Controls.Find("ListBox1", True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is ListBox Then
Dim LB As ListBox = DirectCast(matches(0), ListBox)
LB.Invoke(New MethodInvoker(Sub() LB.Items.Insert(0, DateTime.Now.ToString & ": " & itemName)))
End If
End If
End Sub
I have a listbox on my main vb.net form
This will only work on the startup form, and is not really a good design. Consider other approaches as well:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim soc As New SomeOtherClass
soc.Foo()
End Sub
End Class
Public Class SomeOtherClass
Public Sub Foo()
Dim msg As String = "Hello?!"
Helper.UpdateList(msg) ' <-- You can do this from any class...
End Sub
End Class
Public Class Helper
Public Shared Sub UpdateList(ByVal itemName As String)
Dim frm As Form = My.Application.ApplicationContext.MainForm
If Not IsNothing(frm) Then
Dim matches() As Control = frm.Controls.Find("ListBox1", True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is ListBox Then
Dim LB As ListBox = DirectCast(matches(0), ListBox)
LB.Invoke(New MethodInvoker(Sub() LB.Items.Insert(0, DateTime.Now.ToString & ": " & itemName)))
End If
End If
End Sub
End Class
Other correct approaches, which would require more work on your part, might include:
(1) Pass a reference to your main form into the other classes as you create them. Then those classes can either up the ListBox directly, or possibly call a method in it as suggested by Plutonix. Here's an example of this in action:
Public Class Form1
Public Sub UpdateList(ByVal itemName As String)
ListBox1.Invoke(New MethodInvoker(Sub() ListBox1.Items.Insert(0, DateTime.Now.ToString & ": " & itemName)))
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim soc As New SomeOtherClass(Me)
soc.Foo()
End Sub
End Class
Public Class SomeOtherClass
Private _Main As Form1
Private Sub New()
End Sub
Public Sub New(ByVal MainForm As Form1)
_Main = MainForm
End Sub
Public Sub Foo()
If Not IsNothing(_Main) Then
_Main.UpdateList("Hello?!")
End If
End Sub
End Class
You'd have to modify all of your other classes in a similar fashion so that they can receive an instance of your form.
(2) Make the other classes raise a custom event that the main form subscribes to when those classes are created.

Passing structure as argument through files/functions

I can't get to pass structure as argument through subs/functions in different files of single vbnet project like I use to in earlier MS basic versions.
Here is short example of situation:
Module1.vb
Imports System.IO
Structure mymultitry
Dim index As Integer
<VBFixedString(6)> Dim name As String
Dim weight As Double
End Structure
Module Module1
Public mysetupfile = "mysetup.dat"
Public Sub rwfile(ByVal rw As Integer, ByVal myrecord As Integer, ByVal mmt As mymultitry)
'EDIT: Thanks to SteveDog - proper line should be:
'Public Sub rwfile(ByVal rw As Integer, ByVal myrecord As Integer, ByRef mmt As mymultitry)
Dim fnum As Integer
fnum = FreeFile()
FileOpen(fnum, mysetupfile, OpenMode.Random, OpenAccess.ReadWrite, OpenShare.Shared, Len(mmt))
If rw Then
FilePut(fnum, mmt, myrecord)
Else
FileGet(fnum, mmt, myrecord)
End If
FileClose(fnum)
End Sub
End Module
Form1.vb
Public Class Form1
Dim mmt As mymultitry
Dim mmt1 As mymultitry
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
With mmt
.index = 4
.name = "Helga"
.weight = 128.1445
End With
rwfile(1, 1, mmt) 'write
rwfile(0, 1, mmt1) 'read
'all zero here !?!
Debug.Print(mmt1.index)
Debug.Print(mmt1.name)
Debug.Print(mmt1.weight)
End Sub
End Class
File "mysetup.dat" is reachable and data is saved correctly what I can see with HxD.
But read part seem's to not work as expected.
Please any help on reliable passing structure as argument without too much public elements based on upper example.
I strongly suggest you rewrite your code to use the new .NET IO methods in the System.IO.File class, but, that aside, I think your problem with your existing code is that you need to change your mmt argument from ByVal to ByRef.