see what is attached to a com port and show in combo box - vb.net

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)

Related

String form name to form reference

Basically, I am rewriting some code working for years. Over the time I have many (60+) references to forms - there's a menuitem with OnClick event for each form, where a form reference was created:
Private Sub SomeForm_Click(sender As Object, e As EventArgs) Handles MenuItemForSomeForm.Click
NewTab("Some Form", New SomeForm, 0)
End Sub
...where first parameter is a name to put in a tabPage.Text where the form is opened, second is a new instance of the (particular) form SomeForm and 0 is a default record to display (0 means no default record).
Now, I created a dynamic menu and stored the form names in a database (due to better access control over the access rights, etc). Now, because the menu is generated at runtime, I can't have the OnClick event with separate instance definition of the form and have to create it at runtime, after the MenuItems are created. The side-effect idea was to cut the code short by using only 1 OnClick event or such with MenuItem.Tag paremeter as FormName. Something like:
Private Sub clickeventhandler(sender As Object, e As EventArgs)
Dim tsmi As ToolStripMenuItem = CType(sender, ToolStripMenuItem)
Dim newForm As New >>>FormFrom(tsmi.Tag.ToString)<<< ' only explanation, this won't work
MainW.OpenModuleInTab(new newForm, tsmi.Tag.ToString, 0)
However I am failing to find a way to create form (instances) from this string reference. Reference through collection (i.e. List(of) or Dictionary) would be fine too, I believe.
The structure is obviously:
Object → Form → Form1 (class) → MyForm1 (instance)
I know I can create an object like this:
' Note that you are getting a NEW instance of MyClassA
Dim MyInstance As Object = Activator.CreateInstance(Type.GetType(NameOfMyClass))
I can re-type it to a Form type:
Dim NewForm as Form = CType(MyInstance,Form)
... to acccess some of the form properties like Width, TopLevel, etc., but that's about it. I can't do:
Dim NewForm1 as Form1 = CType(NewForm,Form1)
...because obviously, Form1 comes as a string "Form1".
I don't know how to create a Form1 reference from a "Form1" text (then it would be easy to create an instance) or how to create an instance directly (MyForm1).
SOLUTION
As sugested, I used reflection to get the form. The only way working for me I found was this:
Dim T As Type = System.Type.GetType(FormName, False)
If T Is Nothing Then 'if not found prepend default namespace
Dim Fullname As String = Application.ProductName & "." & FormName
T = System.Type.GetType(Fullname, True, True)
End If
Dim f2 As New Form ' here I am creating a form and working with it
f2 = CType(Activator.CreateInstance(T), Form)
f2.TopLevel = False
f2.Name = FormName.Replace(" ", "") & Now.ToString("yyyyMMddmmhh")
f2.FormBorderStyle = FormBorderStyle.None
f2.Dock = DockStyle.Fill
I am using VB.net CallByName to set public variable and same function to run a sub method (every form contains RecordID variable and LoadRecords sub):
CallByName(f2, "RecordID", CallType.Set, 111)
CallByName(f2, "LoadRecords", CallType.Method, Nothing)
For testing purposes, I put following into the testing form:
Public RecordID As Int32
Public Sub LoadRecords()
MsgBox("Load records!!!!" & vbCrLf & "RecordID = " & RecordID)
End Sub
Activator.CreateInstance(TypeFromName("Form1"))
TypeFromName Function:
Dim list As Lazy(Of Type()) = New Lazy(Of Type())(Function() Assembly.GetExecutingAssembly().GetTypes())
Function TypeFromName(name As String) As Type
Return list.Value.Where(Function(t) t.Name = name).FirstOrDefault()
End Function
So, let's go with the idea that I have an assembly called "WindowsApp2" and in that assembly I've defined Form1 and Form2. I've also created this module in the same assembly:
Public Module Module1
Public Function GetDoStuffWiths() As Dictionary(Of Type, System.Delegate)
Dim DoStuffWiths As New Dictionary(Of Type, System.Delegate)()
DoStuffWiths.Add(GetType(WindowsApp2.Form1), CType(Sub(f) WindowsApp2.Module1.DoStuffWithForm1(f), Action(Of WindowsApp2.Form1)))
DoStuffWiths.Add(GetType(WindowsApp2.Form2), CType(Sub(f) WindowsApp2.Module1.DoStuffWithForm2(f), Action(Of WindowsApp2.Form2)))
Return DoStuffWiths
End Function
Public Sub DoStuffWithForm1(form1 As Form1)
form1.Text = "This is Form 1"
End Sub
Public Sub DoStuffWithForm2(form2 As Form2)
form2.Text = "This is Form 2"
End Sub
End Module
Now, in another assembly "ConsoleApp1" I write this:
Sub Main()
Dim DoStuffWiths As Dictionary(Of Type, System.Delegate) = WindowsApp2.Module1.GetDoStuffWiths()
Dim formAssembly = System.Reflection.Assembly.Load("WindowsApp2")
Dim typeOfForm = formAssembly.GetType("WindowsApp2.Form1")
Dim form As Form = CType(Activator.CreateInstance(typeOfForm), Form)
DoStuffWiths(typeOfForm).DynamicInvoke(form)
Application.Run(form)
End Sub
When I run my console app I get a form popping up with the message "This is Form 1".
If I change the line formAssembly.GetType("WindowsApp2.Form1") to formAssembly.GetType("WindowsApp2.Form2") then I get the message "Wow this is cool".
That's how you can work with strongly typed objects that you dynamically instantiate.
Dim AssemblyProduct As String = System.Reflection.Assembly.GetExecutingAssembly().GetName.Name
Dim FormName As String = "Form1"
Dim NewForm As Object = Reflection.Assembly.GetExecutingAssembly.CreateInstance(AssemblyProduct & "." & FormName)
If TypeOf (NewForm) Is Form1 Then
Dim NewForm1 As Form1 = CType(NewForm, Form1)
NewForm1.BackColor = Color.AliceBlue
NewForm1.Show()
End If

Object reference not set to an instance of object - vb.net

First a little background information: The purpose of this application is to capture images and save them automatically to a network directory that will be either created or appended using the input of the text box. This code DOES work on my computer (windows 7 home 64 bit). I've created it using microsoft visual basic express 2010.
However..... when attempting to run the application on a windows 10 tablet, I get the follow errors:
On form load:
An error occurred while capturing the image. The video capture will now be terminated.
Object reference not set to an instance of an object.
On button2_Click Event:
Object reference not set to an instance of an object.
Below is the entirety of the code.
Form2.vb
Public Class Form2
Public scanIsSet As Boolean
Private webcam As WebCam
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
webcam = New WebCam()
webcam.InitializeWebCam(imgVideo)
webcam.Start()
scanIsSet = False
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim CFGfile As String
Dim SaveDir As String
Dim imgIndex As Integer
Dim existingImages() As String
SaveDir = "C:\somepath\"
'save image to directory with index number
Try
imgCapture.Image.Save(SaveDir & OrderNumber.Text & "\" & CStr(imgIndex) & ".jpg")
Catch ex As Exception
MsgBox("error while accessing object imgCapture" & ex.Message)
End Try
imgIndex = imgIndex + 1
Else
Beep()
MsgBox("Please scan or type in order number first")
End If
End Sub
End Class
WebCam.vb
Imports System
Imports System.IO
Imports System.Linq
Imports System.Text
Imports WebCam_Capture
Imports System.Collections.Generic
Imports ZXing
Imports ZXing.OneD
'Design by Pongsakorn Poosankam
Class WebCam
Public scanz As Boolean
Public Sub setScan(ByVal x As Boolean)
scanz = x
End Sub
Private webcam As WebCamCapture
Private _FrameImage As System.Windows.Forms.PictureBox
Private FrameNumber As Integer = 30
Public Sub InitializeWebCam(ByRef ImageControl As System.Windows.Forms.PictureBox)
webcam = New WebCamCapture()
webcam.FrameNumber = CULng((0))
webcam.TimeToCapture_milliseconds = FrameNumber
AddHandler webcam.ImageCaptured, AddressOf webcam_ImageCaptured
_FrameImage = ImageControl
End Sub
Private Sub webcam_ImageCaptured(ByVal source As Object, ByVal e As WebcamEventArgs)
_FrameImage.Image = e.WebCamImage
If scanz = True Then
Dim BCreader As New ZXing.BarcodeReader
'BCreader.Options.TryHarder = True
Try
Dim resu As Result = BCreader.Decode(e.WebCamImage)
Form2.OrderNumber.Text = resu.Text
setScan(False)
Form2.Label2.Text = ""
Beep()
Catch ex As Exception
'do nothing
End Try
End If
End Sub
Public Sub Start()
webcam.TimeToCapture_milliseconds = FrameNumber
webcam.Start(0)
End Sub
Public Sub [Stop]()
webcam.[Stop]()
End Sub
Public Sub [Continue]()
' change the capture time frame
webcam.TimeToCapture_milliseconds = FrameNumber
' resume the video capture from the stop
webcam.Start(Me.webcam.FrameNumber)
End Sub
Public Sub ResolutionSetting()
webcam.Config()
End Sub
Public Sub AdvanceSetting()
webcam.Config2()
End Sub
End Class
As you can see toward the end of Form2.vb, I've wrapped imgCapture.Image.Save(SaveDir & OrderNumber.Text & "\" & CStr(imgIndex) & ".jpg") in a Try-Catch block because I suspect it's some sort of problems with the pictureBox objects. The try catch block does indeed catch the exception, but I still have no idea what the problem is, why it happens on the tablet and not the PC, or how to fix it.
I've found similar questions, but none with a solution I can make use of.
Since you are using a library, EasyWebCam, that is outdated and not compatible with Win10, I would suggest switching libraries. Other options out there:
DirectX.Capture
Windows.Media.Capture
I FOUND THE SOLUTION BUT I DON'T KNOW IF YOU NEED IT NOW ANYWAY THE PROBLEM IS IF YOU HAVE CHANGED THE PICTUREBOX NAME THEN IN REFENCES USE THE EXACT NAME YOU HAVE CHANGED TO. EXAMPLE IF I CHANGE ALL MY PICTUREBOX NAMES AS -
PictureBox_A1 , PictureBox_A2 ,... and so on then my refence should be as -
Dim r As DataRow
For Each r In t1.Rows
CType(Controls("PictureBox_" & r(2)), PictureBox).Image = bookedicon
Next
MY REFERENCE IS - "PictureBox_"

Bind DataSource to new DevExpress Report Designer?

I'm trying to figure out how to set my DataSource as the default when a user clicks New Report, or for any new report, in the DevExpress User Data Report Designer.
Right now, the Blank Report I have load on Form_Load has my DataSources just fine, but anytime I hit New Report, they're gone.
I've googled and followed the docs, but they all seem to be geared towards opening a specific report (as above).
Can anyone help?
0. ICommandHandler interface
You need to handle the ReportCommand.NewReport command by implementing the ICommandHandler interface. You must pass an object that implementing this interface to the XRDesignMdiController.AddCommandHandler method. You can get XRDesignMdiController object from ReportDesignTool.DesignForm.DesignMdiController property or from ReportDesignTool.DesignRibbonForm.DesignMdiController property according to what type of form you want to use.
Here is example:
Private Sub ShowReportDesigner()
Dim tool As New ReportDesignTool(CreateReport)
Dim controller = tool.DesignRibbonForm.DesignMdiController
Dim handler As New NewCommandHandler(controller, AddressOf CreateReport)
controller.AddCommandHandler(handler)
tool.ShowRibbonDesigner()
End Sub
Private Function CreateReport() As XtraReport
Dim report As New XtraReport
report.DataSource = YourDataSourceObjectHere
Return report
End Function
Public Class NewCommandHandler
Implements ICommandHandler
Private ReadOnly _controller As XRDesignMdiController
Private ReadOnly _createReport As Func(Of XtraReport)
Public Sub New(controller As XRDesignMdiController, createReport As Func(Of XtraReport))
_controller = controller
_createReport = createReport
End Sub
Public Function CanHandleCommand(command As ReportCommand, ByRef useNextHandler As Boolean) As Boolean Implements ICommandHandler.CanHandleCommand
useNextHandler = command <> ReportCommand.NewReport
Return Not useNextHandler
End Function
Public Sub HandleCommand(command As ReportCommand, args() As Object) Implements ICommandHandler.HandleCommand
_controller.OpenReport(_createReport())
End Sub
End Class
1. DesignPanelLoaded event
The another way is to subscribe to XRDesignMdiController.DesignPanelLoaded event. In this event you can check where the DataSource of report in loaded panel is empty and set it to your data source.
Here is example:
Private Sub ShowReportDesigner()
Dim report As New XtraReport
report.DataSource = YourDataSourceObjectHere
Dim tool As New ReportDesignTool(New XtraReport)
Dim controller = tool.DesignRibbonForm.DesignMdiController
AddHandler controller.DesignPanelLoaded, AddressOf mdiController_DesignPanelLoaded
tool.ShowRibbonDesigner()
End Sub
Private Sub mdiController_DesignPanelLoaded(ByVal sender As Object, ByVal e As DesignerLoadedEventArgs)
Dim panel = DirectCast(sender, XRDesignPanel)
Dim report = panel.Report
If IsNothing(report.DataSource) Then
report.DataSource = YourDataSourceObjectHere
End If
End Sub

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.

Programmatically change the startup form on application launch?

Can I programmatically change the startup form on application launch in VB.Net?
Sure you can!
In your Project Properties, set Startup Object to Sub Main, and make sure that there's a Public Sub Main method somewhere in your application. A separate startup class may be a good idea:
Public Class myStartupClass
''' <summary>
''' This is the method that will be run when the application loads,
''' because Project Properties, Startup Object is set to SubMain
''' </summary>
''' <remarks>
''' </remarks>
''' --------------------------------------------------------------------------------
Public Shared Sub Main()
'The form that we will end up showing
Dim formToShow As System.Windows.Forms.Form = Nothing
'The determiner as to which form to show
Dim myMood As String = "Happy"
'Choose the appropriate form
Select Case myMood
Case "Happy"
formToShow = New Form1
Case Else
formToShow = New Form2
End Select
'Show the form, and keep it open until it's explicitly closed.
formToShow.ShowDialog()
End Sub
End Class
In a "Windows Forms Application", created under VB 2010 Express, you can do the following in ApplicationEvents.vb:
Partial Friend Class MyApplication
Private Sub MyApplication_Startup(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
'Select the form of your choice
My.Application.MainForm = Any_Form_You_like
End Sub
End Class
This is the approach I use which effectively starts a form like a normal an application entry point.
Public Sub Main()
Dim value As String = Trim(Environment.CommandLine)
Dim f As Form
Select Case value
Case "a"
f = New frmTextEdit
Case "b"
f = New frmListDialog
Case "c"
f = New frmSuggestion
Case Else
Throw New Exception("Unsupported startup form option")
End Select
Application.Run(f)
End Sub
The right method is change MainForm of project.
Open ApplicationsEvents.vb
At ApplicationStart.vb use:
Private Sub MyApplication_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
Dim formToShow As System.Windows.Forms.Form = Nothing
Dim AM_PM as String = "AM"
Select Case
Case "AM"
Me.MainForm = frmBefore
Case "PM"
Me.MainForm = frmAfter
End Select
MainForm.Show()
End Sub
That's is.