So I have 2 forms and a class, on my 1st form, it adds items to a dictionary and on my second form it checks if the item that is supposed to be added on dictionary is successful. But the weird thing is, in form 1, it shows that the item is added in the dictionary but in my 2nd form, when I get the count of dictionary, it produces 0 which means there's nothing in there. Hope you could help me with this.
Form 1
Public Class register
Dim acc_num As New System.Text.StringBuilder()
Dim account_info As New ArrayList()
Dim access_acc As New Accounts
Private Sub btn_save_Click(sender As Object, e As EventArgs) Handles btn_save.Click
Try
account_info.Add(fname_txt.Text & " " & lname_txt.Text)
account_info.Add("0.00")
access_acc.addAcc(account_number_lbl.Text, account_info)
MsgBox("Your account has been registered! Thank you for banking with us, your money is in good hands")
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
End Class
Form 2
Dim access_acc As New Accounts
Private Sub btn_process_Click(sender As Object, e As EventArgs) Handles btn_process.Click
MsgBox(access_acc.getCount().ToString)
End Sub
My Class
Public Class Accounts
Private account As New Dictionary(Of String, ArrayList)
Public Sub addAcc(ByVal account_number As String, account_info As ArrayList)
account.Add(account_number, account_info)
MsgBox(account.Count)
End Sub
Public Function getCount() As Integer
Return account.Count
End Function
End Class
I got rid of my problem by using Module(which is a C# counterpart to static) instead of Class.
Here's a reference as to what is the best method to use in a certain situation.
Module VS Classes
Related
I have a ComboBox that I use on multiple WinForms. Instead of dropping a ComboBox on each WinForm and then filling the ComboBox with data from a DataTable on each individual WinForm, couldn't I create a User Control (ComboBox) that has the data populated already and just use that UC on my Winforms?
Below is how I fill the data for each individual combobox now. (I have a public class for the sql stuff)
The Variable SQL comes from a Class called SQLControl. the Class has all the sql connection stuff.
Public Sub Fillcombobox()
sql.AddParam("#ExaminerType", 3)
sql.ExecQuery("MyStoredProcedure")
ComboBoxExaminer.ValueMember = "Examiner_ID"
ComboBoxExaminer.DisplayMember = "Last_Name"
ComboBoxExaminer.DataSource = sql.DBDT
End Sub
Private Sub MyWinform_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Call Fillcombobox()
End Sub
You can put a small Class Examiner
Public Class Examiner
Public Property Examiner_ID As Integer
Public Property Last_Name As String
Public Sub New(ID As Integer, lname As String)
Examiner_ID = ID
Last_Name = lname
End Sub
End Class
Then, when the first form loads, get the data in a list declared in a module so it can be accessed from any form in the application. Of course, you may have other things in the Module.
Module Module1
Public ExaminerData As New List(Of Examiner)
End Module
Private Sub MyWinform_Load(sender As Object, e As EventArgs) Handles MyBase.Load
FillExaminerList()
ComboBoxExaminer.ValueMember = "Examiner_ID"
ComboBoxExaminer.DisplayMember = "Last_Name"
ComboBoxExaminer.DataSource = ExaminerData
End Sub
Any other form that needs the data to fill a combo box can use ExaminerData. You only call FillExaminerList once at the beginning of the application. There is only a single hit on the database.
Private OPConStr As String = "Your connection string."
Private Sub FillExaminerList()
Dim dt As New DataTable
Using cn As New SqlConnection(OPConStr),
cmd As New SqlCommand("MyStoredProcedure", cn)
cmd.Parameters.Add("#ExaminerType", SqlDbType.Int).Value = 3
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
For Each row As DataRow In dt.Rows
Dim ex As New Examiner(CInt(row("Examiner_ID")), row("Last_Name").ToString)
ExaminerData.Add(ex)
Next
End Sub
I have a List(of ClassA) which includes a List(of ClassB). This contains a string called “heading”.
I read in a new string using a text box. I want to check if the new string already exists.
My previous code works, but I think it can be done in a more elegant way. I find it a little difficult because I have this class construct. I created a new project for you and only copied the necessary – but reproducible – source code.
Form1.vb
Imports Microsoft.VisualBasic.ControlChars
Public NotInheritable Class FormMain
Private allA As New List(Of ClassA)
Private the_new_String As String = ""
Private Sub FormMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
allA.Add(New ClassA)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For i As Integer = 0 To allA.Count - 1 Step 1
For j As Integer = 0 To allA(i).allB.Count - 1 Step 1
If allA(i).allB(j).Heading = the_new_String Then
MessageBox.Show($"Diesen Titel gibt es bereits.{NewLine}This title already exists.",
"",
MessageBoxButtons.OK,
MessageBoxIcon.Information)
Return
End If
Next
Next
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
the_new_String = TextBox1.Text
End Sub
End Class
ClassA.vb
Public Class ClassA
Public allB As New List(Of ClassB)
Public Sub New()
allB.Add(New ClassB())
End Sub
End Class
ClassB.vb
Public Class ClassB
Public Heading As String = "Test"
End Class
If allA.Any(Function(a) a.allB.Any(Function(b) b.Heading = the_new_String)) Then
'The specified text already exists.
End If
There's nothing wrong with the nested loop that you have. Anything else you do will ultimately compile down to the same nested loop (although the loop statements would likely be hidden in a Linq function call). For example, in the other answer posted, each Any call is hiding a loop.
As another alternative, you could consider using SelectMany, which is the Linq routine for flattening a hierarchy.
The result would be,
If allA.SelectMany(Function(a) a.allB.Select(Function(b) b.Heading)) _
.Any(Function(heading) heading = testString) Then
'Proposed heading already exists
End If
I believe this would end up with similar algorithmic efficiency to your original code or to the code in the other answer. SelectMany, Select, and Any should all use deferred execution, so I think it would break out of the implicit nested loop as soon as a match is found without extra iterations. (It's easy to reason about the set operations that Linq will give you, but it's not necessarily easy to identify the loop complexity that hides behind the statements, especially when some Linq functions will evaluate eagerly and others will defer.)
I have searched through the internet and couldn't find the answer to my problem, but, the issue is that I have 2 forms;
frm_bookManeger
and
frm_addBook
The first one is the main form and has a list of books (named listBook), a TreeView and a button to invoke the second form to add a new book.
After filling in all of the TextBoxes and information of a book, I press "Add". Then, the second form will be closed and all info of that book will be kept in an instance of Book class. The problem is: how can I pass this instance to the first form to store it in listBook.
For example:
If I create a constructor in form 1 to get form 2 then in form 2:
Dim f1 As form1 = New form1(me)
f1.Show()
f2.Close()
I can't do it because form 1 will start up instantly when I start program, and the default right now doesn't have any parameter in OnCreateMainForm():
Protected Overrides Sub OnCreateMainForm()
Me.MainForm = Global.WindowsApplication5.frm1
End Sub
How can I do it?
First form:
Public Class frm_bookManeger
'list of Book
Dim listBook As List(Of Book) = New List(Of Book)
Private frm_addBook As frm_addBook
Public Sub New(frm_addBook As frm_addBook) 'got error
Me.frm_addBook = frm_addBook
End Sub
Second form:
Public Class frm_addBook
Dim Public tempBook As Book = New Book()
'add book
Private Sub btn_add_Click(sender As Object, e As EventArgs) Handles btn_add.Click
tempBook.BookName1 = TextBox_name.Text
tempBook.Author1 = TextBox_author.Text
tempBook.Price1 = TextBox_price.Text
tempBook.Genre1 = TextBox_genre.Text
tempBook.EstablishedDay1 = dtp_established.Value.Date
Dim frm_Mngr As frm_bookManeger = New frm_bookManeger(Me)
End Sub
End Class
Dim frm As New form1
frm.textbox.Text = Me.passing value.Text
frm.Show()
or you can try
Public Class Form1
Private loginLabel As String
Public Sub New(ByVal loginParameter As String)
InitializeComponent()
Me.loginLabel = loginParameter
End Sub
End Class
dim frm as new Form1(label.Text)
Your frm_addBook needs a reference to the instance of frm_bookManeger so that it can use methods in the latter.
That can be done by passing a reference to the current instance of frm_bookManeger to the New constructor of frm_addBook.
Also, you probably want the book adding form to be a dialog form rather than an ordinary form.
I made a simple "Book" class and used a TextBox to display the books, so the first form is this:
Imports System.Text
Public Class frm_BookManager
Dim bookList As List(Of Book)
Public Class Book
Property Name As String
Property Author As String
End Class
Public Sub AddBook(b As Book)
If bookList Is Nothing Then
bookList = New List(Of Book)
End If
bookList.Add(b)
End Sub
Private Sub ShowBooks()
Dim sb As New StringBuilder
For Each b In bookList
sb.AppendLine(b.Name & " by " & b.Author)
Next
TextBox1.Text = sb.ToString()
End Sub
Private Sub btn_add_Click(sender As Object, e As EventArgs) Handles btn_add.Click
Using addBook As New frm_addBook(Me)
Dim result = addBook.ShowDialog()
If result = DialogResult.OK Then
ShowBooks()
End If
End Using
End Sub
Private Sub frm_BookManager_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddBook(New Book With {.Name = "Wuthering Heights", .Author = "Emily Brontë"})
ShowBooks()
End Sub
End Class
For the form to add a book, I added "Cancel" and "OK" buttons.
Public Class frm_addBook
Dim myParent As frm_BookManager
Private Sub bnOK_Click(sender As Object, e As EventArgs) Handles bnOK.Click
Dim b As New frm_BookManager.Book With {.Name = TextBox_name.Text, .Author = TextBox_author.Text}
myParent.AddBook(b)
End Sub
Public Sub New(parent As frm_BookManager)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
myParent = parent
' set the DialogResult for each button so the parent can tell what happened
bnCancel.DialogResult = DialogResult.Cancel
bnOK.DialogResult = DialogResult.OK
End Sub
End Class
Notice that a new Book can be added with myParent.AddBook(b) because myParent refers to an instance of frm_BookManager.
You could modify it so that the dialog stays open and has a button to just add a book and not close the dialog. I made the ShowBooks() method Private so you can't call it from outside the class it is in - you could modify that.
There are many possibilities for small modifications to the code I showed to achieve greater functionality. And I could not resist correcting the spelling of "Maneger" to "Manager" ;)
I think the easiest way would be to have the frm_addBook form have a property which will contain the book that was added. In the frm_bookManager form, show that form using ShowDialog and if the user clicks OK on that form, the property will contain the book added. Be sure to dispose the frm_addBook form after you get the book from the public property.
Public Class Book
Public Property Name As String
Public Property Author As String
End Class
Public Class frm_bookManager
Dim bookList As New List(Of Book)()
Private Sub btnAddBook_Click(sender As Object, e As EventArgs) Handles btnAddBook.Click
Using addBookForm As New frm_addBook()
If addBookForm.ShowDialog() = DialogResult.OK Then
bookList.Add(addBookForm.BookToAdd)
End If
End Using
End Sub
End Class
Public Class frm_addBook
Public Property BookToAdd As Book
Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles
'User filled in the fields and clicked this OK button
Me.BookToAdd = New Book()
Me.BookToAdd.Name = txtName.Text
Me.BookToAdd.Author = txtAuthor.Text
End Sub
End Class
I would not pass the main form instance into the add book form because it would create a tight coupling between the two forms and the add book form would only be usable by the main form. You might wish to use the add book form from other forms in the app.
I currently have about 5 forms in my application. I'm building a 6th form - frmSummary however, I'd like to be able to access it from all forms. in frmSummary I am planning to add a DataGridView, where I'll be displaying data related to that form. I'm thinking that I should either create a global variable such as
dim FrmName as String
In each form I would have a cmdSummary button so that On click_event, I would do something like
frmName ="CustomerInfo"
Currently the way my application is set up is that I hve a mdiForm and within it, each form is a child so on opening new forms I do something like...
Private Sub cmdSummary_Click(sender As Object, e As EventArgs) Handles cmdSummary.Click
Dim NewMDIChild As New frmClientEligibilityReferral()
frmName = "CustomerInfo" --since this will be comeing from frmCustomerInfo
NewMDIChild.MdiParent = MDIform1
NewMDIChild.Show()
MDIForm1.Show()
End Sub
So I do something like that on opening my new form. My question is how can I pass the parameter to my form frmSummary....here's currently what I'm trying to accomplish....
Private Sub FrmSummary_Load(sender As Object, e As EventArgs) Handles Me.Load
Me.MdiParent = MDIForm1
InitializeComponent()
'Here I want to call a function to load the datagridView(with g_frmName)see below...
call LoadDataGrid(frmName)
End Sub
Is something like that a smart idea? Or should I/Can I directly call the function from the previous form?
Just trying to see if I'm on the right track, if not, how can i do it in a sound way?
If there is only one frmSummary, you could make it a singleton.
In frmSummary, put the following code:
Private Shared _instance As frmSummary
Private Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
Public Shared Function GetInstance() As frmSummary
If _instance Is Nothing Then
_instance = New frmSummary()
End If
Return _instance
End Function
Public Sub PutDataInGrid(data As Object)
Me.DataGridView1.' put data in it
End Sub
And you would access it from other forms like this
Dim myFrmSummary = frmSummary.GetInstance()
myFrmSummary.PutDataInGrid(myData)
If I understand the question correctly....
You can just set the required parameters in the New declaration sub (Where InitializeComponent() is supposed to be). On your form, declare variables and set one to each of the parameter values, and set up your form this way..
An example might be;
Public Class frmSummary
Dim var1 as String = ""
Dim var2 as Boolean = True
Public Sub New(ByVal parameter1 as String, ByVal parameter2 As Boolean)
var1 = parameter1
var2 = parameter2
InitializeComponent()
End Sub
Private Sub frmSummary_Load(sender as Object, e As EventArgs) Handles MyBase.Load
If var1 = "This String" Then
If var2 = False Then
sql = "SELECT * FROM myTable"
' Rest of your code to get the DGV data
DataGridView1.DataSource = Dt
Else
End If
End If
End Sub
Again, I may have misunderstood the question, so apologies if that is the case.
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.