I'm trying to understand more about VB.NET and Multiple forms so I can make my code better.
I have a SQL database table that holds the live data for all 14 processes, the monitor program updates a form showing the progress of all the processes. Years ago in MS Access I would have simply used a rolling subform to show the contents of the table.
However, my first attempt in VB.NET is to have "many" textboxes, basically 14 lines of textboxes and my code has 14 very similar parts updating all the textboxes. There has to be a better way :(
For Example:
txtProcessID1.Text TxtStatus1.Text ProgressBar1 ......
txtProcessID2.Text TxtStatus2.Text ProgressBar2 ......
txtProcessID3.Text TxtStatus3.Text ProgressBar3 ......
So, I'm trying to come up with a code where I create a SubForm that looks like one controller line, then create 14 instances of this subform on my mainform.
My test code seems to work but the textboxes on the subforms are not updating the contents on screen!! Even though when I call back the contents of .text it is what I expect.
Why does this example code not work, and is my solution the best way to complete this?
Public Class MainForm
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SubForm.SetText = Me.TextBox1.Text ' Try to change contents of a TextBox on the SubForm
Me.TextBox2.Text = SubForm.SetText ' Data comes back as expected, but the subform textbox remains unchanged.
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim objSubForm As New SubForm()
objSubForm.TopLevel = False
Me.Panel1.Controls.Add(objSubForm)
objSubForm.Show()
End Sub
End Class
Public Class SubForm
Public Property SetText() As String
Get
SetText = TextBox1.Text
End Get
Set(ByVal Value As String)
Me.TextBox1.Text = Value ' Control is not updated of the SubForm.
Debug.Print("Value = " & Value) ' The Value is Passed Correctly.
Debug.Print("Text = " & TextBox1.Text) ' And the property of the control has been updated.
End Set
End Property
End Class
Many Thanks
Kev
In your button click you are referencing the class name SubForm, this in VB.NET is called as the default automatic instance of a form, but this is not the same instance that you display in your Form_Load. Here you create a different instance called objSubForm and this is the instance that you display.
To fix you need to keep the objSubForm as a global instance and refer to this global when you click
Public Class MainForm
Dim objSubForm As SubForm
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
objSubForm.SetText = Me.TextBox1.Text ' Try to change contents of a TextBox on the SubForm
Me.TextBox2.Text = objSubForm.SetText ' Data comes back as expected, but the subform textbox remains unchanged.
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
objSubForm = New SubForm()
objSubForm.TopLevel = False
Me.Panel1.Controls.Add(objSubForm)
objSubForm.Show()
End Sub
End Class
Keep in mind that after this change you are responsible to effectively close and dispose the global instance.
Private Sub Form1_FormClosed(sender as Object, e as FormClosedEventArgs) _
Handles Form1.FormClosed
if objSubForm IsNot Nothing
objSubForm.Close
End If
objSubForm = Nothing
End Sub
Thanks Steve, I applied the new code in just half an hour based on your fix.
Here's a basic example of my code that gives me 14 subforms I can update.
I've moved away from creating a property in the subform in favour of directly updating the TextBox control.
The solution has given me "MUCH" less code and now I can add another detail to the one subform and show that for all processes.
Thanks Again!
Kev
Public Class MainForm
Dim objSubForm(14) As SubForm
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Update the 14 forms
For n = 0 To 13
objSubForm(n).TextBox1.Text = Me.TextBox1.Text & " " & n
Next
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' create 14 subforms
For n = 0 To 13
objSubForm(n) = New SubForm()
objSubForm(n).TopLevel = False
Me.Panel1.Controls.Add(objSubForm(n))
objSubForm(n).Location = New Point(0, 20 * n)
objSubForm(n).Show()
Next
End Sub
Private Sub MainForm_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
' CLear up
If objSubForm IsNot Nothing Then
For n = 0 To 13
objSubForm(n).Close()
Next
End If
For n = 0 To 13
objSubForm(n) = Nothing
Next
End Sub
End Class
Related
I have 2 Datagridview controls in same form. Each Datagrid has some columns where user will write long texts, so I designed form with RichTextBox that opens when user double-clicks these columns to enlarge text-entry. Code works, but I want to use same form for both Datagrids, so I should somehow return text to active datagridview cell. Here is my code (for Datagridview1):
TextZoomForm:
Public Class TextZoomForm
Public OpenedForm1 As New Form1
Private Sub RichTextBox1_DoubleClick(sender As Object, e As EventArgs) Handles RichTextBox1.DoubleClick
OpenedForm1.DataGridView1.CurrentCell.Value = RichTextBox1.Text
OpenedForm1.Label24.Focus()
Me.Close()
End Sub
Private Sub TextZoom_Load(sender As Object, e As EventArgs) Handles Me.Load
RichTextBox1.Text = OpenedForm1.DataGridView1.CurrentCell.Value
End Sub
End Class
DataGridView1_CellMouseDoubleClick in Form1:
Private Sub DataGridView1_CellMouseDoubleClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseDoubleClick
If e.ColumnIndex = 1 Then
Dim cp = Cursor.Position
cp.Y += CInt(Cursor.Size.Height * (-0.5))
cp.X += CInt(Cursor.Size.Width * 0.8)
Dim f As New TextZoomForm()
f.OpenedForm1 = Me
f.Show()
f.Location = New Point(cp)
End If
End Sub
Any ideas on how to return text to active datagridview cell?
Change your zoomed form so that it doesn't know where its data comes from. Instead the control using it will pass the data.
Public Class TextZoomForm
Public Property ZoomedText As String
Get
Return RichTextBox1.Text
End Get
Set(value As String)
RichTextBox1.Text = value
End Set
End Property
Private Sub RichTextBox1_DoubleClick(sender As Object, e As EventArgs) Handles RichTextBox1.DoubleClick
Me.Close()
End Sub
End Class
To call the form change your code to the following:
Private Sub DataGridView1_CellMouseDoubleClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseDoubleClick
...
Dim f As New TextZoomForm()
f.ZoomedText = DataGridView1.CurrentCell.Value
f.ShowDialog()
'Great breakpoint location.
DataGridView1.CurrentCell.Value = f.ZoomedText
Label24.Focus()
....
End Sub
Using ShowDialog prevents the user from changing the current cell part way through your call.
If you need it modeless then you should:
store the cell that the user has selected
handle the FormClosing event.
Test the DialogResult to make sure the user pressed ok
write the data back to the stored cell.
How do I reset a ComboBox to default Text i set in properties. Say I have a ComboBox with default text "Ruby" which when SelectedIndexChanged is printed in TextBox afterwards it does'nt reset to default text "Ruby" but the SelectedItem. I want it to read "Ruby" afterwards or all the time if not possible. Thank you
Declare the helper class variable in the form class:
Dim _originalComboText As String
On opening the form, remember the default text of the control in some helper variable. For example, add the following line into the constructor (Sub New()):
_originalComboText = ComboBox1.Text
Every time after the selection is made, restore the text from it:
ComboBox1.Text = _originalComboText
If you inspect the content of the .designer.vb file belonging to your form, you can actually see initialization of text of your control through the assignment (=) – so vb.net does no special magic here. If you want to preserve the text, you have to save it somewhere before it gets lost.
Here is the complete minimum example:
Public Class Form1
Dim _originalComboText As String
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
_originalComboText = ComboBox1.Text
End Sub
Private Sub ComboBox1_Leave(sender As Object, e As EventArgs) Handles ComboBox1.Leave
ComboBox1.Text = _originalComboText
End Sub
Private Sub ComboBox1_LocationChanged(sender As Object, e As EventArgs) Handles ComboBox1.LocationChanged
ComboBox1.Text = _originalComboText
End Sub
End Class
And if your two handlers do not differ, then replace them just with one – with two events in Handles clause:
Private Sub ComboBox1_RestoreText(sender As Object, e As EventArgs) _
Handles ComboBox1.Leave, ComboBox1.LocationChanged
ComboBox1.Text = _originalComboText
End Sub
Use this:
Private Sub ComboBox1_Leave(sender As Object, e As EventArgs) Handles ComboBox1.Leave
ComboBox1.Text = "Ruby"
End Sub
Private Sub ComboBox1_LocationChanged(sender As Object, e As EventArgs) Handles ComboBox1.LocationChanged
ComboBox1.Text = "Ruby"
End Sub
Since the user will choose, say print <<"EOF"; ---mytext---EOF from dropdown list and this will automatically print on textbox. He or she must go to textbox or somewhere else.
I know its not coventional to answer own question but if anyone needs help. Here it is
I want to pass the value of an exact variable to another form...
To be more precise I'm building a game in which a player answer a few questions so I want to pass the variable that contains the correct answer to another form which works as the end game window and displays the score... I'm using this kind of code in the end game window:
Public Class Form2
Public Property CCount As Integer
Private Sub Form5_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Text = CCcount
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
CCount = 0
Form1.Show()
Me.Close()
End Sub
End class
And this in the main form:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Lines of code
Form2.CCount +=1
'Lines of code
'Me.Hide()
'Form2.Show()
EndSub
The first time that I'm "playing the game" everything works fine, but if try to replay it the displaying scores never changes... It remains the same as the first run..
Any ideas how I can fix this out?
You assign value of CCount to the Label only ones when form was loaded.
Load event raised only one time.
Put label updating code inside CCount Property Setter
Private _CCount As Integer
Public Property CCount As Integer
Get
Return _CCount
End Get
Set (value As Integer)
If _CCount = value Then Exit Property
_CCount = value
Me.Label1.Text = _CCount.ToString()
End Set
End Property
I am still learning on vb.net but I have main form (form1) that has 2 columns. One called Red and the other Yellow. I have a button that opens a form (form2) that has a textbox that allows the user to put in someone's name and a combobox to select a color. What I am trying to accomplish it when they click the submit button on form2, the name will show up in the proper column in form1. Both colors on form1 has their own textbox under it. Red has textbox1 and Yellow has textbox2. Can anyone assist on how I would go about doing this? I am using Visual Studio 2010 VB.Net. Thanks!!
Danny
So many ways to do this...here's another one.
Code in Form1:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim f2 As New Form2
If f2.ShowDialog = Windows.Forms.DialogResult.OK Then
Select Case f2.ComboBox1.SelectedItem.ToString.ToLower
Case "red"
TextBox1.AppendText(f2.TextBox1.Text & Environment.NewLine)
Case "yellow"
TextBox2.AppendText(f2.TextBox1.Text & Environment.NewLine)
Case Else
MessageBox.Show("Unkown Color!")
End Select
End If
End Sub
End Class
and in Form2:
Public Class Form2
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.DialogResult = Windows.Forms.DialogResult.Cancel
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If TextBox1.TextLength > 0 AndAlso ComboBox1.SelectedIndex <> -1 Then
Me.DialogResult = Windows.Forms.DialogResult.OK
End If
End Sub
End Class
From a simple workflow perspective, you can have Form 2 call a method on Form 1 and provides the new name and color. Form 1 would then add the name to the correct column. There are a number of ways to handle this- one would be to have Form 1 instantiate form 2 then pass in a delegate reference for the method that will take the name and color.
So in Form 1 -
Public Sub HandleAdd(name as String, color as String)
' Do Stuff Here.
End Sub
Public Sub AddPlayerButton_Click(sender as Object, e as EventArgs) Handles AddPlayerButton.Click
Dim frm As New Form2
frm.AfterAdd = AddressOf HandleAdd
frm.Show
End Sub
And in Form 2 -
Public Property AfterAdd As Action(of String, String)
Public Sub OKButton_Click(sender as Object, e as EventArgs) Handles OK.Click
If AfterAdd IsNot Nothing Then AfterAdd(playerName.value, playerColor.value)
End Sub
Or something like that.
So basically you have a main form that shows only a label (lblTotalPrice) and a button that when you click it, it opens a second form that contains a listbox with different prices packages (lstPackages). How do do you select an item from lstPackages that is on the second form and return it to lblTotalPrice, which is located on the main form?
I attempted this code using a function (thought it would be useful for calculations), but it seems like it didn't work:
On my second form, I populated the lstPackages with it's name using parallel arrays:
Dim strPackages As String = {"Package 1", "Package 2", "Package 3", "Package 4", "Package 5"}
Dim decPrice As String = {100D, 200D, 300D, 400D, 500D}
Private Sub SecondForm_Activated(sender As Object, e As EventArgs) Handles MyBase.Activate
Dim frmMain as New
Dim i As Integer
For i = 0 To strPackages.Length - 1
lstPackages.Items.Add(strPackages(i))
Next
End Sub
After I tried to select a value on lstPackages, but I just was not too sure if I was using the right code to select the item and return it to the main form:
Function CalcPackage()
Dim decPackages As Decimal = 0D
If lstPackages.SelectedIndex = -1 Then
MessageBox.Show("Select a package")
Else
For i = 0 To lstPackages.SelectedItem - 1
decPackages = lstPackages.SelectedItem(i)
Next i
End If
Return decPackages
End Function
When I have selected the item in the lstPackages, I tried to send the selected item back to the main form, but ran into a problem here:
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnClose.Click
Dim frmMainForm As New MainForm
Dim decTotal As Decimal
decTotal = CalcPackage()
'I was stuck in this part and wasn't sure how to return it to lblTotalPrice (and also close the second form too)
frmMainForm.lblTotalPrice.Text = decTotal.ToString("c")
frmMainForm.Show()
Me.Close()
End Sub
So yea sorry if my code is weird, but I'm hoping to get help on how to return the value of the item to lblTotalPrice on the main form, thanks guys
Part of your problem is that you are newing up an instance of the main form in the button exit click event handler of the second form, as shown in this code posted:
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnClose.Click
Dim frmMainForm As New MainForm
Dim decTotal As Decimal
decTotal = CalcPackage()
'I was stuck in this part and wasn't sure how to return it to lblTotalPrice (and also close the second form too)
frmMainForm.lblTotalPrice.Text = decTotal.ToString("c")
frmMainForm.Show()
Me.Close()
End Sub
Instead pass an instance of the main form to the second form via its constructor, like this:
Public Class SecondForm Inherits Form
Dim theMainForm As MainForm
Public Sub New(mainForm As MainForm)
theMainForm = mainForm
End Sub
End Class
Now you can reference the lblTotalPrice in the MainForm class via the theMainForm variable, like this:
theMainForm.lblTotalPrice.Text = lstPackages.SelectedItem
The theMainForm.lblTotalPrice.Text should only be updated in response to an item being selected from lstPackages not when the second form is closed; so handle the updating of the main form's label in the SelectedIndexChanged event of lstPackages, like this:
Protected Sub lstPackages_IndexChanged(sender As Object, e As EventArgs)
Dim decTotal As Decimal
decTotal = CalcPackage()
theMainForm.lblTotalPrice.Text = decTotal.ToString("c")
End Sub
All the exit button click event handler should do is to show the main form and close the second form, like this:
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnClose.Click
theMainForm.Show()
Me.Close()
End Sub
Just display SecondForm with ShowDialog(), then retrieve the value with the reference to it that you already have:
Public Class MainForm
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim sf As New SecondForm
If sf.ShowDialog = Windows.Forms.DialogResult.OK Then
lblTotalPrice.Text = sf.TotalPrice
End If
End Sub
End Class
Over in SecondForm:
Public Class SecondForm
Private _TotalPrice As Decimal
Public ReadOnly Property TotalPrice As Decimal
Get
Return _TotalPrice
End Get
End Property
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnClose.Click
If lstPackages.SelectedIndex = -1 Then
MessageBox.Show("Select a package")
Else
_TotalPrice = lstPackages.SelectedItem(0)
Me.DialogResult = Windows.Forms.DialogResult.OK
End If
End Sub
End Class