Data doesn't display when working with multiple forms - vb.net

I'm new to VB.NET and have been struggling all afternoon with something. I've found similar questions on the forum but none of them seemed to describe my problem exactly. I'm fairly sure that I'm missing something very basic.
I have made a main form which currently holds only one button which purpose is to open up a second form and close the main form. Based on the settings the user will select on the 2nd form the first form might have to be adapted to match with the new settings. But the problem occurs even before that.
The 'settings' form has 15 textboxes which I drew onto the form in development mode. They are called ID1, ID2,..,ID15. The values which I want to display in there are saved in an array:
Dim ids(15) as integer
Next, I created a module to simulate what you could call a control array as I used to use them in VB6.
Public sources() As TextBox = [frmSettings.ID1, frmSettings.ID2, //and so on
I did this to be able to iterate through all the 15 textboxes:
For i = 0 To 14
Sources(i).Text = ids(i + 1)
Next
Then I added on the main form this code to the Button1_Click() event:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
frmSettings.Show()
Me.Close()
End Sub
I did the same thing for the 'exit ' button on the frmSettings form.
This seems to work, but only once. I launch the application, push the button and frmSettings pops up and shows all the values from the array in the textboxes. When I push the 'close' button, I return to the main page.
So far so good, but if I try to return to frmSettings a second time, all the textboxes remain blank as if the code I added to the form never gets executed.
Any help would be greatly appreciated!

First, make sure the array that holds your data is accessible to both forms:
Module Module1
Public ids(15) As Integer
End Module
There should not be a declaration for "ids" in either form.
Next, make frmSettings itself responsible for loading and saving the data:
Public Class frmSettings
Private Sub frmSettings_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim matches() As Control
For i As Integer = 0 To 14
matches = Me.Controls.Find("ID" & (i + 1), True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is TextBox Then
Dim TB As TextBox = DirectCast(matches(0), TextBox)
TB.Text = ids(i)
End If
Next
End Sub
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
Dim valid As Boolean = True
Dim matches() As Control
For i As Integer = 0 To 14
matches = Me.Controls.Find("ID" & (i + 1), True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is TextBox Then
Dim TB As TextBox = DirectCast(matches(0), TextBox)
Dim value As Integer
If Integer.TryParse(TB.Text, value) Then
ids(i) = value
Else
MessageBox.Show(TB.Name & ": " & TB.Text, "Invalid Value", MessageBoxButtons.OK, MessageBoxIcon.Warning)
valid = False
End If
End If
Next
If valid Then
Me.Close()
End If
End Sub
End Class

Related

Cannot set focus to textbox

I am using VB and trying to select a portion of the text in a textbox of a separate form. However, I can't seem to find a good way to access the textbox from the other form, although the textbox is public (I am new to VB).
Currently, I'm trying to do this by calling a function located in the form (the form with the textbox), and then focusing on the textbox and selecting/highlighting the text. But it still doesn't work:
Public Sub GetFindLoc(ByVal lngStart As Long, ByVal intLen As Integer)
frmFind.Hide()
MessageBox.Show(ActiveForm.Name)
MessageBox.Show(txtNotes.CanFocus())
txtNotes.Focus()
txtNotes.Select(lngStart, intLen)
frmFind.Show()
End Sub
With this, I first hide the original form, and then try to select the text, and bring back the form. It shows that the active form is the one which I'm trying to select the text on, but it returns false on CanFocus().
Any help would be appreciated, thank you!
Hmm. This was more fiddly than I thought. You need to pass a reference to the other form:
Main form:
Public Class frmNotes
'This is the main form
'This form has a textbox named txtNotes and a button called btnShowFind
'txtNotes has .MultiLine=True
Private mfrmFind As frmFind
Private Sub btnShowFind_Click(sender As Object, e As EventArgs) Handles btnShowFind.Click
If mfrmFind Is Nothing OrElse mfrmFind.IsDisposed Then
mfrmFind = New frmFind(Me)
mfrmFind.Show()
Else
mfrmFind.BringToFront()
End If
End Sub
End Class
Finder form:
Public Class frmFind
'This form has a textbox called txtFind and a button called btnFind
Private mfrmParent As frmNotes
Sub New(parent As frmNotes)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
mfrmParent = parent
End Sub
Private Sub btnFind_Click(sender As Object, e As EventArgs) Handles btnFind.Click
If txtFind.Text = "" Then
MsgBox("Please enter text to find", MsgBoxStyle.Exclamation)
Exit Sub
End If
Dim intSearchBegin As Integer = mfrmParent.txtNotes.SelectionStart + 1
Dim intStart As Integer = mfrmParent.txtNotes.Text.IndexOf(txtFind.Text, intSearchBegin)
If intStart > -1 Then
mfrmParent.txtNotes.Select(intStart, txtFind.Text.Length)
mfrmParent.txtNotes.Focus()
mfrmParent.BringToFront()
Else
mfrmParent.txtNotes.Select(0, 0)
MsgBox("No more matches")
End If
End Sub
End Class
Public Class frmFind
Private Sub btnFind_Click(sender As Object, e As EventArgs) Handles btnFind.Click
Dim search As String = TextBox1.Text.Trim
Dim pos As Integer = frmNotes.txtNotes.Text.IndexOf(search)
If pos > 0 Then
frmNotes.txtNotes.Focus()
frmNotes.txtNotes.Select(pos, search.Length)
End If
End Sub
End Class
This is just a "find" form with 1 textbox and 1 button which will highlight the first occurrence of the string in TextBox1 that it finds in txtNotes on the other form. If you want it to find whitespace as well, then remove the Trim function. You can add code to find other occurrences or go forward/backward.

get ID from datagridview and show the data to another form in textboxes

Im kind of new in vb.net. I have a datagridview that shows the Delivery Number, Date and supplier. Now, I want the Admin to view the details of every delivery to another form. I just want to know how will I get the id of the selected row and then will be able to display the equivalent data of that selected ID. Thanks.
Here's my code for the Deliveries Form.
Private Sub dgvDeliveryReport_CellContentDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgvDeliveryReport.CellContentDoubleClick
If e.RowIndex < 0 Then Exit Sub
Dim id As Int32 = dgvDeliveryReport.CurrentRow.Cells(0).Value
Dim viewDelivery As New frmDeliveryFormReport
frmDeliveryFormReport.Show()
End Sub
In your frmDeliveryFormReport class add a new field to store current row:
private _currentDeliveryReportRow as DataGridViewRow
Look for the constructor:
Public Sub New frmDeliveryFormReport()
...
End Sub
(If you cannot find it just proceed with the next step).
Change/Add the constructor so it takes the DataGridViewRow parameter and store the given row:
Public Sub New frmDeliveryFormReport(deliveryReportRow as DataGridViewRow)
_currentDeliveryReportRow = deliveryReportRow
End Sub
Adapt your existing dgvDeliveryReport_CellContentDoubleClick to call the new constructor:
Private Sub dgvDeliveryReport_CellContentDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgvDeliveryReport.CellContentDoubleClick
If e.RowIndex < 0 Then Exit Sub
Dim viewDelivery As New frmDeliveryFormReport(dgvDeliveryReport.CurrentRow)
frmDeliveryFormReport.Show()
End Sub
You can then access all columns of the DeliveryReportRow in the frmDeliveryFormReport via
_currentDeliveryReportRow.Cells(<CellIndex>)
Additional information about this topic:
Passing variables between windows forms in VS 2010
VB.Net Passing values to another form
http://www.dreamincode.net/forums/topic/332553-passing-data-between-forms/
Try.
Dim newFrmName as new yourForm
For each row as DataGridViewRow in SampleGrid
if row.selected = true then
Dim whatValueYouWant as string = row.cells("ID").value.toString()
if newFrmName.NameOfTextBoxInForm.Text <> vbEmpty Then
'NameOfTextBoxInForm is textbox that existing in yourform
newFrmName.NameOfTextBoxInForm.text = ", " & whatValueYouWant
Else
newFrmName.NameOfTextBoxInForm.text = whatValueYouWant
End If
End IF
Next
newFrmName.Show()

adding multiple textbox .net

What i want is when i input a number in texbox1.text like for example i enter 3 it should show 3 textbox but i always get an error. and also i have to save it in database but i dont know how. Help Please..
Private boxes(TextBox1.text) As TextBox
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim newbox As TextBox
For i As Integer = 1 To TextBox1.Text
newbox = New TextBox
newbox.Size = New Drawing.Size(575, 35)
newbox.Location = New Point(10, 10 + 35 * (i - 1))
newbox.Name = "TextBox" & i
newbox.Text = newbox.Name
'connect it to a handler, save a reference to the array and add it to the form controls
AddHandler newbox.TextChanged, AddressOf TextBox_TextChanged
boxes(i) = newbox
Me.Controls.Add(newbox)
Next
End Sub
OK. The error I get when I try to run your code is :-
An unhandled exception of type 'System.InvalidCastException' occurred in Microsoft.VisualBasic.dll
Additional information: Conversion from string "" to type 'Integer' is not valid.`
This is because you're trying to start a loop using a string as the termination index for the loop. Try using
For i As Integer = 1 To Val(TextBox1.Text)
your next problem will depend on how you've declared boxes. If you have declared it like this ..
Dim boxes() As TextBox
You'll end up with a Null reference exception because when you declared boxes, you didnt supply any elements. To remedy this you'll need to add this just before your loop ..
ReDim Preserve boxes(Val(TextBox1.Text))
If boxes is a list.. and to be honest .. thats a better choice than an array, instead of the above line you'll need to change
boxes(i) = newbox
to
boxes.Add(newbox)
You might also need to change other code associated with boxes, but the work will be worth it.
Your biggest problem is that you're trying to get a value from a TextBox that hasn't even appeared yet. You've put your code inside the form's load event. It really needs to be in a separate method. Oh and rather than use the TextBox.changed event you should use a button control to execute the method. Otherwise it's too easy for someone to change the number in the textbox. With your code, each time the textbox is changed (deleting a digit or adding another digit), more TextBoxes will be added and you could end up with lots of them.
So possible final code should look like ..
Public Class Form1
Dim boxes As New List(Of TextBox)
Private Sub Addbuttons(buttonCount As Integer)
Dim newbox As TextBox
For i As Integer = 1 To buttonCount
newbox = New TextBox
newbox.Size = New Drawing.Size(575, 35)
newbox.Location = New Drawing.Point(10, 10 + 35 * (i - 1))
newbox.Name = "TextBox" & i
newbox.Text = newbox.Name
'connect it to a handler, save a reference to the array and add it to the form controls
boxes.Add(newbox)
Me.Controls.Add(newbox)
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Addbuttons(Val(TextBox1.Text))
End Sub
End Class

How to create Control Arrays in VB .NET

In VB6 there is a feature called Control Arrays, where you name controls the same name and provide them an index value. This allows you to set a value by looping through the controls and setting each value. In VB .NET I can't create a control array could someone provide me with a similar solution.
Here is a sample I wrote for something else that shows how to do something similar and shows how to do the handler as well. This makes a 10x10 grid of buttons that turn red when you click them.
Dim IsCreated(99) As Boolean
Dim Buttons As New Dictionary(Of String, Button)
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
For i As Integer = 0 To 99
Dim B As New Button
Me.Controls.Add(B)
B.Height = 30
B.Width = 40
B.Left = (i Mod 10) * 41
B.Top = (i \ 10) * 31
B.Text = Chr((i \ 10) + Asc("A")) & i Mod 10 + 1
Buttons.Add(B.Text, B)
B.Tag = i
AddHandler B.Click, AddressOf Button_Click
Next
End Sub
Private Sub Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim B As Button = sender
IsCreated(B.Tag) = True
B.BackColor = Color.Red
End Sub
Avoid using the proposed iteration approaches, you'll get a fairly random collection of controls unless your form is very simple. Simply declare the control array in your code and initialize it in the form constructor. Like this:
Public Class Form1
Private OrderNumbers() As TextBox
Public Sub New()
InitializeComponent()
OrderNumbers = New TextBox() {TextBox1, TextBox2}
End Sub
End Class
You can now treat OrderNumbers just like you could in VB6.
Maybe this is simpler. To create a control array, I put the control array declaration in a module. For example, if I have a Form with three TextBoxes and I want the TextBoxes to be part of a control array called 'mytext', I declare my control array in a module as follows:
Module Module1
Public mytext() As TextBox = {Form1.TextBox1, Form1.TextBox2, Form1.TextBox3}
End Module
And, I use the TextBoxes from the control array as follows:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
mytext(0).Text = "Hello"
mytext(1).Text = "Hi"
mytext(2).Text = "There"
End Sub
End Class
You can even loop through the control array, like you could in VB6:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
For i As Integer = 0 To 2
mytext(i).Text = i + 1
Next
End Sub
End Class
The beauty of using a module is that the TextBoxes do not even need to be in the same form.
With Winforms, you could do this:
myForm.Controls _
.OfType(Of TextBox) _
.OrderBy(Function(c) c.Name) _
.Where(Function(c) c.Name.StartsWith("somePrefix")) _
.ToArray()
On your form you would name your textboxes somePrefix1, somePrefix2, etc.
Here is an old article but it could give you more information. The top method is super easy.
Your Form, or PanelControl, or anything else that can contain child controls will have a Property called Controls.
You can loop through all of the text boxes in a control by using
'Create a List of TextBoxes, like an Array but better
Dim myTextBoxControls As New List
For Each uxControl As UserControl in MyFormName.Controls
If TypeOf(uControl) is TextBox
myTextBoxControls.Add(uControl)
End IF
Next
Now you have your iterate-able collection you can work with.
You can access a TextBoxes value with the EditValue property.
After looking at what you're trying to do a little further.
You probably want to name all of your controls with a Prefix, let's say abc for now.
For Each uxControl As UserControl in MyFormName.Controls
If TypeOf(uControl) is TextBox Then
Dim tbControl As TextBox = DirectCast(uControl, TextBox)
If tbControl.Name.StartsWith("abc") Then
tbControl.EditValue = "the Value you want to initialize"
End If
End If
Next
So this is one of the features that did not make the transition to VB.NET -- exactly :-( However, you can accomplish much of what you would have done in VB6 with two different mechanisms in .NET: Looping through the controls collection and handling control events.
Looping Through the Controls Collection
In VB.NET every form and control container has a controls collection. This is a collection that you can loop through and then do an operation on the control like set the value.
Dim myTxt As TextBox
For Each ctl As Control In Me.Controls
If TypeOf ctl Is TextBox Then
myTxt = CType(ctl, TextBox)
myTxt.Text = "something"
End If
Next
In this code sample you iterate over the controls collection testing the type of the returned object. If you find a textbox, cast it to a textbox and then do something with it.
Handling Control Events
You can also handle events over multiple controls with one event handler like you would have using the control array in VB6. To do this you will use the Handles keyword.
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged, TextBox2.TextChanged, TextBox3.TextChanged
Dim myTxt As TextBox = CType(sender, TextBox)
MessageBox.Show(myTxt.Text)
End Sub
The key here is the Handles keyword on the end of the event handler. You separate out the various controls that you want to handle and the event by using a comma. Make sure that you are handling controls that have the same event declaration. If you ever wondered what sender was for on every event well here's one of the uses for it. Cast the sender argument to the type of control that you are working with and assign it to a local variable. You will then be able to access and manipulate the control that fired the event just like you would have in VB6 if you specified and index to the array.
Using these two techniques you can replicate the functionality of control arrays in VB6. Good luck.
Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
Dim a() As Control = GetControls("textbox")
For Each c As TextBox In a
c.Text = c.Name
Next
End Sub
Private Function GetControls(typeOfControl As String) As Control()
Dim allControls As New List(Of Control)
'this loop will get all the controls on the form
'no matter what the level of container nesting
'thanks to jmcilhinney at vbforums
Dim ctl As Control = Me.GetNextControl(Me, True)
Do Until ctl Is Nothing
allControls.Add(ctl)
ctl = Me.GetNextControl(ctl, True)
Loop
'now return the controls you want
Return allControls.OrderBy(Function(c) c.Name). _
Where( _
Function(c) (c.GetType.ToString.ToLower.Contains(typeOfControl.ToLower) AndAlso _
c.Name.Contains("Box")) _
).ToArray()
End Function

Search ListBox elements in VB.Net

I'm migrating an application from VB6 to VB.Net and I found a change in the behavior of the ListBox and I'm not sure of how to make it equal to VB6.
The problem is this:
In the VB6 app, when the ListBox is focused and I type into it, the list selects the element that matches what I type. e.g. If the list contains a list of countries and I type "ita", "Italy" will be selected in the listbox.
The problem is that with the .Net version of the control if I type "ita" it will select the first element that starts with i, then the first element that starts with "t" and finally the first element that starts with "a".
So, any idea on how to get the original behavior? (I'm thinking in some property that I'm not seeing by some reason or something like that)
I really don't want to write an event handler for this (which btw, wouldn't be trivial).
Thanks a lot!
I shared willw's frustration. This is what I came up with. Add a class called ListBoxTypeAhead to your project and include this code. Then use this class as a control on your form. It traps keyboard input and moves the selected item they way the old VB6 listbox did. You can take out the timer if you wish. It mimics the behavior of keyboard input in Windows explorer.
Public Class ListBoxTypeAhead
Inherits ListBox
Dim Buffer As String
Dim WithEvents Timer1 As New Timer
Private Sub ListBoxTypeAhead_KeyDown(sender As Object, _
e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
Select Case e.KeyCode
Case Keys.A To Keys.Z, Keys.NumPad0 To Keys.NumPad9
e.SuppressKeyPress = True
Buffer &= Chr(e.KeyValue)
Me.SelectedIndex = Me.FindString(Buffer)
Timer1.Start()
Case Else
Timer1.Stop()
Buffer = ""
End Select
End Sub
Private Sub ListBoxTypeAhead_LostFocus(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.LostFocus
Timer1.Stop()
Buffer = ""
End Sub
Public Sub New()
Timer1.Interval = 2000
End Sub
Private Sub Timer1_Tick(sender As Object, e As System.EventArgs) Handles Timer1.Tick
Timer1.Stop()
Buffer = ""
End Sub
End Class
As you probably know, this feature is called 'type ahead,' and it's not built into the Winform ListBox (so you're not missing a property).
You can get the type-ahead functionality on the ListView control if you set its View property to List.
Public Function CheckIfExistInCombo(ByVal objCombo As Object, ByVal TextToFind As String) As Boolean
Dim NumOfItems As Object 'The Number Of Items In ComboBox
Dim IndexNum As Integer 'Index
NumOfItems = objCombo.ListCount
For IndexNum = 0 To NumOfItems - 1
If objCombo.List(IndexNum) = TextToFind Then
CheckIfExistInCombo = True
Exit Function
End If
Next IndexNum
CheckIfExistInCombo = False
End Function