How to get all forms in a VB.net (VS08) project in an array? - vb.net

Alright, so I need a method that traverses all the forms inside a VB.net project under Visual Studio 2008, and create an array of type form with references to all the forms inside it, so that the array looks like this (pseudocode)
FormsArray() = [Form1, Form2, Form3, Form4]
However, I don't have a clue as to how to begin.

You have to adjust the function to put the result of msgbox in a array
Public Sub getallforms(ByVal sender As Object)
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In sender.GetType().Assembly.GetTypes()
If UCase(t.BaseType.ToString) = "SYSTEM.WINDOWS.FORMS.FORM" Then
MsgBox(t.Name)
End If
Next
End Sub
You must call the function from any form in the application like this (getallforms(me))

Here is how you would do this using Reflection, assuming that the class where you placed this code was in the same assembly that you wanted to iterate over. If not, then you'll need to change the Me.GetType().Assembly in the For Each loop into something else to account for loading the assembly in a different manner.
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.IsSubclassOf(formType) = True Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next

Hey this is what I did to get the list of forms in my vb project, how ever this in not in code but you could write system.io code fragment to do just that.
open cmd prompt
go to project folder
run a dir /s/b *.designer.vb >> list.txt
use notepad or sublimetext and edit it to get the list ordered as you like it.
:) hope this helped!

I could not get this version to work:
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.IsSubclassOf(formType) = True Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next
In VB2010 formType is always Nothing
So I dumped the formType line and simply modified your 'IF' statement to check the BaseType instead. Here is the New Version
Dim Forms As New List(Of Form)()
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.BaseType.Name = "Form" Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next

You need to either write a VS macro or an Addin.
In it, from a DTE or DTE2 instance, you can write:
Public Sub GetForms(ByVal host As DTE2)
Dim project As Project = host.ActiveDocument.ProjectItem.ContainingProject
For Each ce As CodeElement In project.CodeModel.CodeElements
If ce.Kind = vsCMElement.vsCMElementClass Then
Dim cl As CodeClass = CType(ce, CodeClass)
If cl.IsDerivedFrom("System.Windows.Forms) Then
'do something
End If
End If
Next
End Sub

2 options
I would load the actual project file into a XML reader. Then iterate all the nodes looking for all Form SubTypes and store the linked files in an array. If the name of file matches the name of the form class, you can create your FormsArray from that list. Otherwise you have to load each file and look for the public class definition of the file to get the list.
Using Reflection, examine the project using Assembly.GetTypes. Find all the System.Windows.Forms.Form Types and store them in a list. Then write out the Type.Name.

Related

VB store list of records in a text file and read back

I have a VB program in VS2017. It reads many excel files and store relevant data in
Dim total_sessions As New List(Of Session_CSV_file)
The list is big (~10k), and includes about 20 fields each.
Is there a way in VB to store it in a file in one command and read it later on easily., without reading and writing each field?
Often I need to debug the later part. I prefer doing it without rerunning the whole first part.
Or is there a way in Visual Studio, to stop the run at a certain point, and store this point in a dump file, like simulators often do? (so they can run the simulation from this point later on)
Perhaps if you load your csv data into a DataTable instead:
Dim dt as New DataTable
dt.Columns.Add("Name")
dt.Columns.Add("Age", GetType(Int32))
For Each filepath in tenKFilePaths
For Each line in File.ReadAllLines(file)
Dim bits = line.Split(","c)
dt.Rows.Add(bits(0), Convert.ToInt32(bit(1))
Next line
Next filepath
Then you can save the whole lot to xml:
dt.WriteXml("c:\temp\my.xml")
Have a coffee, reboot etc the read them again and carry on where you left off:
Dim dt2 as New DataTable
dt2.ReadXml("c:\temp\my.xml")
Raw datatables are a bit difficult to work with because you end up accessing their rows and column data by string indexing and having to cast it a lot - fairly lame. There is a better way to use them, as visual studio can create custom classes that inherit from the base datatables and offer lots of functionality that does away with all the awkwardness of dealing with datatables as a very generic thing. Just like the forms designer creates a UI form that inherits from Form, the dataset designer creates custom datatables that inherit from the base
If you add a new DataSet type object to your project, double click it it opens something like a database designer. Right click that surface and choose Add DataTable, Add your Columns with their respective datatypes etc - this is the equivalent of your Session_Csv_File class, with its properties and fields. Double click on it and you can add code etc - if your session_csv_file has custom methods you can transfer their code to the custom data row
Imagine I created a new datatable in a DataSet and called it SessionCsvFiles. Imagine I added a Name and Age column, and I added a custom method called BlahBlah
I'd then be able to say in code things like:
Dim dt as New MyCustomDataSet.SessionCsvFilesDataTable
'it's like making a new SessionCsvFile
Dim r = dt.NewSessionCsvFilesRow()
'It's like setting your properties
r.Name = csvBits(0)
r.Age = Convert.ToInt32(csvBits(1))
'It's like adding your file to the List
dt.Add(r)
You now have virtually the same thing as you had before - a collection of objects that represents things about your csv files. The difference is with this route it has an already-built-in way of saving all the properties and the collection to xml and reading it back again
Add the Serializable attribute to the Class. I added a parameterized constructor for ease in building my list but you must provide a constructor without parameters for this to work. Thus, the empty Sub New.
<Serializable()>
Public Class Session_CSV_file
Public Property ID As Integer
Public Property Name As String
Public Property Type As String
Public Sub New()
End Sub
Public Sub New(SessID As Integer, SessName As String, SessType As String)
ID = SessID
Name = SessName
Type = SessType
End Sub
End Class
The add Imports System.Xml.Serialization to the top of the file.
Private Sub SaveList()
Dim serializer = New XmlSerializer(GetType(List(Of Session_CSV_file)))
Using writer As New StreamWriter("C:\Users\xxx\Documents\XMLtest.xml")
serializer.Serialize(writer, lst)
End Using
End Sub
I filled my list as follows but you can fill you list any way you choose.
Private lst As New List(Of Session_CSV_file)
Private Sub FillList()
Using cn As New SqlConnection(My.Settings.CoffeeConnection),
cmd As New SqlCommand("Select Top 10 * From Coffees;", cn)
cn.Open()
Dim reader = cmd.ExecuteReader
While reader.Read
Dim sess As New Session_CSV_file(reader.GetInt32(0), reader.GetString(1), reader.GetString(3))
lst.Add(sess)
End While
End Using
End Sub
To recreate the list... (OOps! forgot this)
Private RehydratedList As New List(Of Session_CSV_file)
Private Sub CreateListFromXML()
Dim serial As New XmlSerializer(GetType(List(Of Session_CSV_file)))
Using fs As New FileStream("C:\Users\maryo\Documents\XMLtest.xml", FileMode.Open)
RehydratedList = DirectCast(serial.Deserialize(fs), List(Of Session_CSV_file))
End Using
For Each item In RehydratedList
Debug.Print(item.ToString)
Next
End Sub

Set a Property Value From Database of Properties

My database has the formname, control, and control property type value stored.
I would like to have a line of code like this.
Forms(i%).Controls(ControlName$)).controlpropertytype$ = NewValue
I am currently using a select case structure to handle the various property types. It would be much simpler to have a single statement take care of it.
Using a helper function, you can achieve this with one line of code. Here's an example of setting a TextBox on Form1 to the value 'aaa':
Option Explicit
Private Sub Test()
CallByName FindForm("Form1").Controls("Text1"), "Text", VbLet, "aaa"
End Sub
Public Function FindForm(ByVal Name As String) As Form
Dim f As Form
For Each f In Forms
If UCase(f.Name) = UCase(Name) Then
Set FindForm = f
Exit Function
End If
Next
End Function
While this is an interesting exercise, I would not recommend this approach. It assumes the form and the control can both be found, but if they can't be found this one-liner will crash your app.
Here's documentation for CallByName.

VB.NET multithreading functions

So I've been working on a program that will find all files from a directory and subdirectories and my application is "freezing" while executing because its single-threaded, but I don't know how to multithread a function with an argument in it. so the use is like getallfiles("C:/Folder") and after this it will add each file in a listbox using the following code.
Private Sub getallfiles(filelocation As String)
Try
For Each item As String In My.Computer.FileSystem.GetFiles(filelocation)
If Path.GetExtension(item) = My.Settings.scanfor & "filter" Then
Me.Invoke(Sub() ListBox1.Items.Add(item))
Me.Invoke(Sub() ListBox1.SelectedIndex = ListBox1.Items.Count - 1)
End If
Next
For Each folder As String In My.Computer.FileSystem.GetDirectories(filelocation)
Me.Invoke(Sub() getallfiles(folder))
Next
Catch ex As Exception
End Try
End Sub
and I'm trying to use Thread1 = New System.Threading.Thread(AddressOf getcache(item))
Error BC30577 'AddressOf' operand must be the name of a method
(without parentheses).
if you know any ways of fixing or doing this, I would be happy to hear your answer
Instead of using the vb file functions try the .net System.IO functions. With Directory.GetFiles("Path of Directory to search", "*.txt", SearchOption.AllDirectories) you can search with an extension filter as the second parameter and the last parameter will search all sub-directories. Don't add your items one by one to the listbox. That would be very slow because the listbox has to redraw on each iteration. The GetFiles function returns an array of Strings. You can add this all at once with the listbox items .AddRange Don't forget to add Imports System.IO at the top of the file.
https://msdn.microsoft.com/en-us/library/ms143316(v=vs.110).aspx
Dim FilesFromDir() As String = Directory.GetFiles("C:\Users\maryo\Documents\TextNotes", "*.txt", SearchOption.AllDirectories)
ListBox3.Items.AddRange(FilesFromDir)

Loading My.Settings in other solution

I need to load My.settings from the first Solution into the Second.
In the first project I have a helper class for getting the Settings.
Public Class format
Public NotInheritable Class Helper
Private Sub New()
End Sub
Public Shared Function getAppSetting() As String
Dim returnValue As Object = My.Settings.format
If returnValue Is Nothing Then
Return String.Empty
Else
Return returnValue.ToString
End If
End Function
Public Shared Function getAppSettingTheme() As String
Dim returnValue_theme As Object = My.Settings.theme_selected
If returnValue_theme Is Nothing Then
Return String.Empty
Else
Return returnValue_theme.ToString
End If
End Function
End Class
End Class
This class I have implemented in the other Solutions (Even addiction I have a set)
In other Solutions I have the code for getting the Settings.
Imports MyProject.format.Helper
MsgBox(getAppSettingTheme())
But in the MsgBox I see Default Settings (Unchanged) While in the first solution displays the user-changed settings.
My.Settings I have saved [My.settings.save]
If you choose to do this in a complicated way,what you have to do is,make classes in the first project to read My.Settings,then reference the project in the other project and use it...
However,i'll rather describe an easier way(tho the above one is not that hard) to achieve your goal.
Firstly,i believe that you are using My.Settings to store some data,right ?If so,you can simply save the data to a text file and read it from anywhere you want.This will save plenty of your code and make it tidy :)
As you seem to be a beginner,i would try to keep it as simple as possible and explain in the simplest words...
Now,let's assume,you have 4 My.Settings entries as follows :
UserName
Password
Phone
Age
Instead of writing this data in My.Settings,write it to a text file.Let's assume a user inputs relevant data and it looks somewhat like this :
Zack Rayan
1212121
+090990809809
20
To write a text file, you can simply use File.WriteAllText but as we see that here,our data is in multiline,we can make use of the following :
FIle.WriteAllLines
File.AppendText
Well,let's use File.AppendText method(you can use the below code with WriteAllText as well :)) :
File.AppendText("C:\test.mycustomExtension" , "Zack Rayan" + Environment.NewLine + "1212121" + Environment.NewLine + "+090990809809" + Environment.NewLine + "20")
This will write a text file for you containing the given data in separate lines as well as you will have your own custom extension for the file :)
Now,how to use it ?
Simple :
Dim ReadFile as New List(Of String)(File.ReadAllLines("C:\Test.mycustomextension"))
Now,let's assume,when you were using My.Settings, you used some codes like this :
If My.Settings.UserName = "Zack" Then
......
Scroll up and look closely.UserName was your first entry in My.Settings and when we wrote the text file,ZACK RAYAN-the assumed username was also written in the first line
A few lines above, i created a list which reads the text file.It needs no saying that it will read(and store) the first line first and then move on gradually. So,where you used :
If My.Settings.UserName = "Zack" Then
u should now use :
If ReadFile(0) = "Zack" Then
I hope this helps to enrich your knowledge :)

How to close parent form and open child?

Hey guys before I was just hiding the parent form, but now when I try to read from the parent file it says it can't because it's already running in a process. I followed some tutorial and it said to go to the project properties and have the application stop running when all the forms are closed.
But now since I did that it says the directory can't be found probably because I am reading the input from the parent form. Anyways here is my code
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" + frmLogin.txtUser.Text))
How should I go about doing this?
Edit:
Private Sub btnHunter_Click(sender As System.Object, e As System.EventArgs) Handles btnHunter.Click
selection = "Hunter"
writeData.classSelection()
End Sub
This is what I have when the button is clicked.
Here is the classSelection sub:
Public Sub classSelection()
If frmClass.selection = "Hunter" Then
writeFile1.WriteLine(frmClass.selection)
End If
If frmClass.selection = "Gatherer" Then
writeFile1.WriteLine(frmClass.selection)
End If
If frmClass.selection = "Farmer" Then
writeFile1.WriteLine(frmClass.selection)
End If
writeFile1.Close()
End Sub
The error points to this line:
If frmClass.selection = "Hunter" Then
Saying part of the file path cannot be found.
If you want to read input textbox in closed parent form, you have to declare public var
Make a new module in your project .. and add this
public sLogin as String
And before you hide or close frmLogin .. add this
sLogin = txtUser.Text
So, you could change your code with
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" & sLogin))
matzone has given you a good hint. And to check exactly what your path is, just add a MessageBox using variables :
Dim writePath1 As String
Dim writeFile1 As StreamWriter
writePath1 = "C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" & sLogin
If MessageBox.Show(writePath1, "Continue ?", MessageBoxButtons.YesNo) = DialogResult.Yes Then
writeFile1 = New StreamWriter(File.OpenWrite(writePath1))
' ...
writeFile1.Close() ' Very important ! Adrian pointed it out.
End If
^^ and if it works, you can discard the Dialog test or replace it by some test code like If File.Exists(...)
However, I don't understand wether you want to close the parent Form or hide it. It's different !
Closing the parent Form will discard any access to parent Form members, including txtUser.Text.
If you want to close the parent Form, the ChildForm should not be a child of that parent you are trying to close, or you must just hide the parent Form :
frmLogin.Hide() ' Not frmLogin.Close()
If you close frmLogin, frmLogin.txtUser won't be accessible, or use sLogin provided by matzone instead. Alternatively, you should pass frmLogin.txtUser.Text value to a custom property of ChildForm.
Imports System.IO
Public Partial Class ChildForm1
' Inherits System.Windows.Form
' ...
Private _txtUserFile As String
Public WriteOnly Property TxtUserFile() As String
Set(ByVal NewFileName As String)
_txtUserFile = NewFileName
End Set
End Property
Public Sub LoadFile()
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" & txtUserFile))
' ...
writeFile1.Close()
End sub
' ...
End Class
Then use this in parent Form :
MyChildForm.TxtUserFile = Me.txtUser.Text
' Me.Close() ' This will definately KILL Form1 (the parent one)
Me.Hide() ' Always use Hide() until you'll terminate your Application
MyChildForm.Show()
MyChildForm.LoadFile()
^^ but this is not a good code either ! Your problem remains unclear (at least for me)
"Still saying it can't find part of the path", then check the path..
Does the file actually exists ?
Does the path contains glitch ? (use the provided MessageBox test)
Does your account can access that directory ? (Windows configuration and account levels)
Well !
In fact, the problem could be somewhere else.
For example, I was able to reproduce your exception by providing an empty string [""] as the value of, either :
frmLogin.txtUser.Text ' = ""
' or
sLogin ' = ""
' or
txtUserFile ' = ""
In fact, I get the "Could not find a part of the path..." exception because the StreamWriter couldn'd read/write to a File, as I didn't provided a valid FileName for that file. As the filename parameter was an empty string "", the provided path for StreamWriter was just representing a directory instead of a file and an exception was raised.
Now, you should check wether you have a valid path before building a new instance of StreamWriter to get sure you are actually pointing to a File ?
Dim writeFile1 As StreamWriter
Dim MyEntirePath As String = "C:\Users\...\Accounts\" + frmLogin.txtUser.Text
MessageBox.Show(MyEntirePath) ' would be enough to be sure your path is correct
' Some test code here...
If everythingOK then ' create the StreamWriter...
writeFile1 = New StreamWriter(MyEntirePath)
' ...
' ...
Also, it's not a good idea to create your streamwriter, and use it in another part/method of your code. You never known if one day, you'll change your code, and forget to make the link between
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" + frmLogin.txtUser.Text))
' plus
Private Sub btnHunter_Click(sender As System.Object, e As System.EventArgs)
...
End Sub
' plus
Public Sub classSelection()
...
writeFile1.Close()
End Sub
^^ too much "here and there"...
You'll obviously also get an exception if you try to click btnHunter twice.. I don't know what is the purpose of your code nor how it works, it looks like a game.. But I would use File.Exist(..) checks, create the file before, if none, and put that in a Try/Catch to check if I eventually don't have administrator rights to write to that directory. Otherwise, make a code that allow user to read/write files to a custom folder. Andalso, you have :
Application.StartupPath
^^ Very usefull, like :
Dim MyFilePath As String = Application.StartupPath + "\Datas\MyText.txt"
After two weeks of coding, I usually forget where I put those "C:\blabla.." or "D:\gnagna\" or what classes actually uses those absolute reference paths. I've dropped this way of getting directories long ago since the day I moved to Win7 on another computer and all such applications I developped using that approach was doomed...