How to store a variable after form closes for use later on another form - vb.net

So I am building a form based application, and I am running into an issue with passing data between forms. I have a combo box that, based on selection, triggers a new form to open with several buttons to pick from. Once you select a button, the form closes, but I can't get the selection to be carried over to the original form.
basic idea of the code is like this
Public Class frmMain
Public intStore As integer
Private Sub cboSample_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboSample.SelectedIndexChanged
Dim selection as Integer
selection = cboSample.SelectedIndex
If selection = -1 Then
Else
Select Case selection
Case 0
frmOne.Show()
Case 1
frmTwo.Show()
End Select
End If
End Sub
End Class
Here is a sample of the second form code
Public Class frmOne
Public storage As varStorage
Private Sub btn_Clicked(sender As Object, e As EventArgs) Handles btn.Clicked
storage = New varStorage With {.datastore = 1}
Me.Close()
End Sub
End Class
frmTwo is pretty much the same but handles more options
The Class I created looks like this
Public Class varStorage
Public _dataStore As Integer
Public Property dataStore() As Integer
Get
Return _dataStore
End Get
Set (value As Integer)
_dataStore = value
End Set
End Property
End Class
as I said, the issue comes from the point of the form being called, and the form closing, the variable data is not being saved. I am almost certain I am missing some code somewhere, but not sure where. any help would be greatly appreciated.

Rather than using Show() to open another form, using ShowDialog() will open the form modally. The form will behave like a MessageBox. It will wait for you to respond to, and close, this form before returning to your main form. We can obtain a value from this modal-form, safe in the knowledge that the form has been closed (and so the value we have obtained will not be changed).
The other way is to make a Public Property of the form. then you can create Get and Set methods to have access to your form objects
Public Class yourFormClass
Public Property Note As String
Get
Return txtNote.Text
End Get
Set(value As String)
End Set
End Property
End Class
and Then you can use it like
dialog = New yourFormClass()
someOtherTextbox.Text = dialog.Note

Related

parse value from datagrid to button name

I'm building a form that has many buttons, all buttons do the same thing: add 1 every time they are clicked. Every pressed button is sent to a datagridview along with the time they are pressed. Datagrid values look like this:
a_1_serv (button name), 18:05:00(time).
Sometimes I want to delete the last row. Everything works fine so far.
When I delete the last row, I want to change the text of the button (a_1_serv).
I can parse the dgv value (a_1_serv) to a variable but I can't bind it to the appropriate button name so I can control it.
Is there a way to do it?
Don't store your program state in your UI
Create a data structure to hold the information, and let the DataGridView be a "view", not treating it as a variable. You will save yourself headaches vs using the UI as a variable.
That said, create a class to represent your information
Public Class Data
Public Sub New(button As Button, time As DateTime)
Me.Button = button
Me.Time = time
End Sub
<System.ComponentModel.Browsable(False)>
Public Property Button As Button
Public ReadOnly Property Text As String
Get
Return Button.Name
End Get
End Property
Public Property Time As DateTime
End Class
And your code can manipulate the data in a variable off the UI. Bind the data to the DataGridView for display.
Private datas As New List(Of Data)()
Private Sub Button_Click(sender As Object, e As EventArgs) Handles Button1.Click, Button2.Click, Button3.Click, Button4.Click
addButton(DirectCast(sender, Button))
End Sub
Private Sub RemoveLastButton_Click(sender As Object, e As EventArgs) Handles RemoveLastButton.Click
removeLast()
End Sub
Private Sub addButton(b As Button)
datas.Add(New Data(b, DateTime.Now))
bindData()
End Sub
Private Sub removeLast()
Dim b = datas.Last.Button
b.Text = "new text" ' change to whatever
datas.RemoveAt(datas.Count - 1)
bindData()
End Sub
Private Sub bindData()
DataGridView1.DataSource = Nothing
DataGridView1.DataSource = datas
End Sub
This does exactly what you stated but there may be inconsistency in these two bits of information you provided: a_1_serv (button name) and I want to change the text of the button .... This changes the button text but not the name. The name is displayed in the grid. You can change the data class to display the text or whatever. But the point is this approach will keep your data off the UI and you won't need to look up the control by name anymore.

Check whether a form is loaded (even if Minimized)

I have declared a form as
Private _fUpdate As frmUpdate
There are all kinds of solutions to check if a form is open and visible.
However, if a form is Minimized and not shown in the taskbar, it doesn't show up in Application.OpenForms.
Also Form.IsHandleCreated returns false with the above window state.
If Not uForm Is Nothing returns True even if the form has not yet been instanciated, so it isn't usuable as well.
Is there another way to check whether a form is loaded then a variable storing the window existance and hidden/shown state?
What I usually do if I need to get the instance of a form from somewhere else within my application, is create a Shared property in your form called Instance or something similar and set it in the form's Load event.
With this instance property, you can call it from anywhere else in your application, and use the WindowState property of your form to check its state.
Example of the form:
Public Class frmUpdate
Public Shared Property Instance As frmUpdate
Private Sub OnLoad(sender As Object, e As EventArgs) Handles MyBase.Load
Instance = Me
End Sub
End Class
Example usage in some other method:
Private Sub DoSomething()
If (frmUpdate.Instance.WindowState = FormWindowState.Minimized)
'Do something
End If
End Sub

How to pass a form, object or data to a second form

I have created 2 forms.
The first one is the button that you want to back up.
In the second there are paths that can be modified.
How to make a reference that after pressing the "backup" button will get a path of 2 forms.
The path is saved when I closed form2
I know how to do it in one form but unfortunately I can not refer to another form.
Source of Form 2:
Private Sub Browser_from1_Click(sender As Object, e As EventArgs) Handles Browser_from1.Click
Dim FolderBrowserDialog1 As New FolderBrowserDialog
FolderBrowserDialog1.ShowDialog()
TextBox1from.Text = FolderBrowserDialog1.SelectedPath
If Browser_from1.Text <> "" And TextBox1from.Text <> "" Then
Backup.StartCopy.Enabled = True
End If
End Sub
Private Sub Browser_to1_Click(sender As Object, e As EventArgs) Handles Browser_to1.Click
Dim FolderBrowserDialog1 As New FolderBrowserDialog
FolderBrowserDialog1.ShowDialog()
TextBox2to.Text = FolderBrowserDialog1.SelectedPath
If Browser_to1.Text <> "" And TextBox2to.Text <> "" Then
Backup.StartCopy.Enabled = True
End If
End Sub
Private Sub TextBox1from_TextChanged(sender As Object, e As EventArgs) Handles TextBox1from.TextChanged
End Sub
Private Sub save_settings_Click(sender As Object, e As EventArgs) Handles save_settings.Click
My.Settings.pathmem = TextBox2to.Text
My.Settings.pathmem1 = TextBox1from.Text
My.Settings.Save()
End Sub
Private Sub setting_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TextBox1from.Text = My.Settings.pathmem1
TextBox2to.Text = My.Settings.pathmem
End Sub
End Class
You dont want to create a reference to a form - that would (or could) create a whole new form. You want to hold onto the form reference.
This is done by passing a reference to the forms, but the talk of one form fiddling with the controls on another form is a bad idea because it breaks encapsulation. But forms are classes (it says so at the top of each one), so you can add Properties and Methods (Sub and/or Functions) to facilitate passing information back and forth.
Method One - Passing a Form Reference
The simplest way is to pass whatever the other form needs in the constructor:
' form 1 / "main" form / form to return to
Dim frm As New Form6(Me)
frm.Show()
Me.Hide()
In order for this to work, you need to modify the constructor (Sub New) on the destination form:
Private frmReturnTo As Form
Public Sub New(f As Form)
' This call is required by the designer.
InitializeComponent()
frmReturnTo = f
End Sub
It is best not to create your own constructor until you are familiar with them. Use the drop downs at the top of the code window: from the left pick the form name; from the right, select New. The designer adds required code to them which must not be changed.
Do not add any code before the InitializeComponent() call at least until you are familiar with the life cycle of a form. The form and its controls do not exist until that runs.
To return to the "main" form:
If frmReturnTo IsNot Nothing Then
frmReturnTo.Show()
End If
You may want to remove some of the title bar buttons or add code to the form Closing event to handle when the user closes via the system menu or buttons.
Using the constructor is ideal for cases where there is some bit of data which the form must have in order to do its job.
Method Two - Passing Data
Thats all well and good, but what about passing data to another form? You can use the constructor for that too. In order to pass say, a string, integer and a Point:
' destination / second form:
Public Sub New(a As String, b As Int32, c As Point)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Label1.Text = a
Label2.Text = b.ToString
Label3.Text = c.ToString
End Sub
Call it like this:
' method two: pass data you want to share in the ctor
Dim frm As New frmData("hello", 6, New Point(150, 550))
frm.Show()
Result:
Method Three: Properties
Thats fine, but if there is a lots of data that way can get cumbersome. Plus, you may want to update some of the data from the calling/main form. For this you can create Properties on the form to handle the data:
Public Property Label1Text As String
Get
Return Me.Label1.Text
End Get
Set(value As String)
Me.Label1.Text = value
End Set
End Property
Rather than a private variable to act as the backing field, one of the controls is used. The name leaves a bit to be desired as it exposes implementation details. So, use names which describe what the data represents rather than where it displays.
Public Property SpecialValue As Integer
Get
Return Integer.Parse(Me.Label2.Text)
End Get
Set(value As Integer)
Me.Label2.Text = value.ToString
End Set
End Property
Public Property SomePoint As Point
Get
Dim data = Me.Label3.Text.Split(","c)
Return New Point(Convert.ToInt32(data(0)),
Convert.ToInt32(data(1))
)
End Get
Set(value As Point)
Me.Label3.Text = value.X.ToString & "," & value.Y.ToString
End Set
End Property
A point was used just to show that other data types can be used. Setting those values from the calling/original/source form:
Using frm As New Form6
frm.Label1Text = "Ziggy"
frm.SpecialValue = 42
frm.SomePoint = New Point(111, 222)
frm.ShowDialog()
' do stuff here with any changes
Dim theint = frm.SpecialValue
End Using ' dispose of dialog
The destination controls would well have been TextBoxes for the user to edit. The Property "wrappers" allow you to fetch those values back, so in this case, a Dialog was used.
Method Four: Methods
You can also use methods as a way to pass data to the second/helper form. Here a List(of T) collection will be passed. In the child/display form a method is added to receive the data which it then displays. The task represented is proofing or viewing a filtered list:
Public Sub UpdateDisplay(lst As List(Of SimpleItem), filter As String)
DataGridView1.DataSource = lst
Label1.Text = String.Format("{0} Total {1} Items", lst.Count, filter)
End Sub
In the main/calling form:
' form level variable
Private frmDV As frmDataView
elsewhere...perhaps in a Click event:
' myList is a simple list of items
' Users pick which color to filter on via a combo box
Dim filter As String
If cboListFilter.SelectedItem IsNot Nothing Then
'Dim frmDV As New frmDataView
If frmDV Is Nothing OrElse frmDV.IsDisposed Then
frmDV = New frmDataView
End If
filter = cboListFilter.SelectedItem.ToString()
' apply the filter
Dim tmpList = myList.Where(Function(w) w.Color = filter).ToList()
frmDV.UpdateDisplay(tmpList, filter)
frmDV.Show()
Else
Return
End If
Result:
With DataBased apps a modified version of this can allow for the case where you display DataGridView data in detail form on another form. You need not have the second form rung SQL to add or update the record, and then the main form running another query to "refresh" the display. If the DataSource is a DataTable backed up by a fully configured DataAdapter, pass the DataTable and have the child form add, change or delete using that. The data will automagically be in the DataTable and DataGridView`.
There are other ways to do this, but they generally all boil down to passing something from A to B. Which way is "best" depends on what the app does, the use-case and the nature of the data. There is no one right way or best way.
For instance, Properties and in many cases Functions allow the B Form to close the feedback loop. With DB items, a DataChanged property might tell the calling form that data was added or changed so that form knows to use the DataAdapter to update the db.
'SECOND FORM
Public class secondForm (blah blah)
Public overloads property owner as myMainForm
'Must be only the form you prepared for that
Private sub secondForm_load(blah blah) handles blah blah
Texbox1.text=Owner.customcontrol.text
End sub
End class
'MAIN FORM
public class myMainForm(blah blah)
Private sub button1_click(blah blah) handles blah blah
Dim NewSecondForm as secondForm = New secondForm
NewSecondForm.owner(me)
NewSecondForm.show(me)
NewSecondForm.dispose()
' so you can have bidirectional communication between the two forms and access all the controls and properties from each other
End sub
End Class

passing form textbox value to another form in same project

I currently have 2 forms. 1 holds user data and is modifiable. The other is a display/read only form.
I am trying to pull data (tbUSI.text) from ReportSettings and pass it to Form1 and display it on my UserData.text control.
I have tried using public properties but to no avail. I would rather use public properties, since its cleaner. Here is the code im using to set the property:
Public Property UserSignedInto As String
Get
Return tbUSI.Text
End Get
Set(value As String)
End Set
End Property
Here is my code attempting to call that property on the main form (form1)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
UserData.text = UserSignedInto
End Sub
It doesn't pull anything, the textbox on my main form is blank.
Take a look here:
SCCMReports = New ReportSettings
UserData.text = SCCMReports.UserSignedInto
When was the SCCMReports form ever displayed to the user? Since it was never displayed, its tbUSI.Text value will of course be empty because the user never had an opportunity to enter text.
It sounds like you need a reference to an existing instance of ReportSettings, rather than creating a new instance. Where do you have that existing instance?
If Form1 created the instance in another block of code, store it in a class-level member on Form1 (perhaps called SCCMReportsInstance or something of that nature). When the instance is created, set it to the value of that property and reference that property in your code:
UserData.text = Me.SCCMReportsInstance.UserSignedInto
If the ReportSettings form is instead creating the instance of Form1 then it can pass a reference to itself. You'd still have a property on Form1, it would just be set in the constructor. Something like this:
Sub New(ByVal sccmReportsInstance As ReportSettings)
Me.SCCMReportsInstance = sccmReportsInstance
End Sub
So when initializing the Form1 instance, you'd pass the reference:
Dim form1 As Form1
form1 = New Form1(Me)
form1.Show()
Any way you go about it, you need to access the existing instance of the displayed form in order to access its properties. A new instance would have new versions of those properties and wouldn't have the same values.

Initialize not properly make with classes vb.net

So, I need to do an program for a client and he wants a search bar in it. So I made it and everything worked perfectly but I put it in my main form. Now, I want to put it in a class but when I initialize the program, it gives me the following error
An error occurred while creating the form. For more information,
see Exception.InnerException. The error is: The form is self-reference during
construction from a default instance, which led to infinite recursion. In the
constructor of the form, refer to the form using 'Me'.
I tried to put Me.Rbtn_X... but it doesn't recognize it.
Initialization
' Main form
Public Sub New()
InitializeComponent()
Initialize_search()
End Sub
Initialize_search()
' Main form
' search is initialize like this :
' Dim search as New Research
Private Sub Initialize_search()
search.generate_autocomplete()
End Sub
generate_autocomplete()
' Research class
Sub generate_autocomplete()
' Main_form = Main form
Dim field = ""
' This is the place where the program fail
If Main_form.RbtnR_avancee_contact.Checked Then
field = "personneressource"
Else
field = "beneficiaire"
End if
' ....
End Sub
Is there something I didn't understand or It's not possible to do it that way?
Edit: added Form_shown event
Public Sub New()
InitializeComponent()
' Initialize_search()
End Sub
Private Sub Form_personne_Shown(sender As Object, e As EventArgs) Handles Me.Shown
MessageBox.Show("You are in the Form.Shown event.")
End Sub
The form is not created (fully) until New completes. By adding your Initialize_search to it, it eventually leads to the statement `Main_form.RbtnR_avancee_contact.Checked'. This is wrong on two counts:
1) the form doesnt exist yet, so you cant refer to it. (this is what the error meant with 'form is self-reference during construction')
2) the ref should be Me.RbtnR (which is what it meant by 'refer to the form using 'Me'')
Move your Initialize_search to the Form_shown event. Your code should look like this (including Lar's suggestion)
' Main form
Public Sub New()
' REQUIRED
InitializeComponent()
End Sub
If there is really something that needs to be setup for this, add it to the form_shown event:
Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.Shown
' NOTE: even .NET refers to ME not MainForm etc
InitializePanel
InitializeSeach
End Sub
Then:
Private Sub Initialize_search()
search.generate_autocomplete(Me.RbtnR_avancee_contact.Checked)
End Sub
Then:
Sub generate_autocomplete(AdvContact as Boolean)
Dim field AS STRING = ""
If AdvContact Then
field = "personneressource"
Else
field = "beneficiaire"
End if
' ....
End Sub
Your search class doesn't have a reference to the instance of the form's controls.
Try passing the value instead:
Sub generate_autocomplete(advancedChecked As Boolean)
Dim field As String = ""
If advancedChecked Then
field = "personneressource"
Else
field = "beneficiaire"
End if
End Sub
Then when you call it:
search.generate_autocomplete(Me.RbtnR_avancee_contact.Checked)
Even if did work like you want it to, according to your code, it would always result in field containing the same value (whichever was set in designer).
Instead, try putting this code inside RbtnR_avancee_contact.Checked event. Or even TextChanged for the autocomplete box (and initialize it for the first time user enters anything), it would examine the checked state and populate autocomplete items.
With this approach, if your user never uses the search box, you don't need to initialize it.