I am working on a project that has WebBrowsers in Other Forms;
I wrote the code below to control these WebBrowsers; but I need the code to recognize (Declare) the WebBrowsers of these forms.
Dim openForm As Form = Nothing
For Index As Integer = My.Application.OpenForms.Count - 1 To 0 Step -1
openForm = My.Application.OpenForms.Item(Index)
If openForm IsNot Me Then
MyWebBrowser.navigate("http://www.google.com/") ' PROBLEM IN THIS LINE
End If
Next
My Module created them as below:
Module MMMBrowser
Dim frmNew As New Form
Dim MekdamBrowser As New WebBrowser
Other info gleaned from comments:
there is form factory of some sort which creates new frmNew
there are many of these open at a time, which is the reason for the backwards loop thru OpenForms to find the last one.
The MekdamBrowser reference is an attempt to refer to the browser on the form.
The easy things is to provide a way for outsiders to tell the form to navigate somewhere using a new Sub, and let the form drive the browser control. This probably eliminates the need for a global MekdamBrowser reference. In the browser form add something like this:
Public Sub GotoNewURL(url As String)
myWebBrowserName.navigate(url)
End Sub
This procedure only exists for Form1 not the generic Form type, so we need to change how you find the form to use. Your existing loop is wonky. It will only ever find the last instance of a form which is not the current form. If you add a third form type, it wont work well:
Dim lastBrowserFrm As Form1 ' use the class name!
' this will try to get the last Instance of Form1
lastBrowserFrm = Application.OpenForms.OfType(Of Form1)().LastOrDefault
' LastOrDefaultcan return nothing if there are none,
' so test
If lastBrowserFrm IsNot Nothing Then
lastBrowserFrm .GotoNewUrl("www.stackoverflow.com")
Else
' create a new one, I guess
End If
Your loop was not considering that there could be other form types in the collection which are not Form1 or even if a new browser form was the last one created! This is more important now because GotoNewURL is only available on Form1 instances.
I changed the name to lastBrowserFrm to reflect what is really going one - it will just find the last one created. If you are trying to work with a specific instance, you need to provide a way to track the ones you create such as with a List(of Form1) or use the Name property so you can tell one from the other. As is, you do not a way to get back a specific form instance.
Related
I know this appears to be a rather common topic and should have been resolved from earlier posts. But what I am experiencing still does not seem to have a solution online:
I have a form called ExpenseEntry in which there is a sub procedure called Public Sub OpenVoucher.
I want to call this sub from another form for which I use the following code:
Dim ExpForm As New ExpenseEntry
ExpForm.Show()
ExpForm.OpenVoucher()
While this works well enough, the problem is everytime I click the button, a new window of ExpenseEntry is launched. As per how I have designed the application, repeat windows is not permissible and only one window should be available at a time.
I have tried various methods to restrict more than one form such as by using a variable to control the form but that gives rise to other issues.
If I use Application.OpenForms but still does not resolve the issue.
I have earlier queried in this regard in the following link:
Textbox not refreshing
I am using VB.NET 2019 which does not allow the launch of default instance of a form like Form.Show. I know this is bad practice but it was easier to manage with that till VB.NET 2017.
Now by creating a form variable and launching that creates an infinite loop where I cannot have just one instance of a form running on a single thread.
The really simple way to handle this is to use the default instance of the form type. In VB, since 2005, each form type has a default instance that you can access via the type name. Read here for more info. In your case, you can do this:
'Display the form if it is not already displayed.
ExpenseEntry.Show()
'Activate the form if it is already displayed.
ExpenseEntry.Activate()
'Do the deed.
ExpenseEntry.OpenVouncher()
That said, default instances are a bit dodgy. They do enable beginners to access forms from anywhere in their project under certain circumstances but they also have limitations that can cause issues. Most importantly though, they help to prevent you learning proper OOP by treating forms differently to other types. If you want to do this the way a proper developer would then simply declare a variable to refer to the current instance of the form:
Private expenseEntryDialogue As ExpenseEntry
When it's time to use the form, you simply check whether that variable refers to a usable instance and use it if it does, otherwise create a new one:
If expenseEntryDialogue Is Nothing OrElse expenseEntryDialogue.IsDisposed Then
expenseEntryDialogue = New ExpenseEntry
End If
expenseEntryDialogue.Show()
expenseEntryDialogue.Activate()
expenseEntryDialogue.OpenVoucher()
A third option would be to implement your own singleton, i.e. a type that can only ever have a single instance. You probably wouldn't do that in VB, given that the default instance is basically a thread-specific singleton and does more automatically but, if you wanted to, you could do this:
Public Class ExpenseEntry
Private Shared _instance As ExpenseEntry
'The one and only instance of the type.
Public Shared ReadOnly Property Instance As ExpenseEntry
Get
If _instance Is Nothing OrElse _instance.IsDisposed Then
_instance = New ExpenseEntry
End If
Return _instance
End Get
End Property
'The constructor is private to prevent external instantiation.
Private Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
End Class
and then this:
ExpenseEntry.Instance.Show()
ExpenseEntry.Instance.Activate()
ExpenseEntry.Instance.OpenVoucher()
I know this has been answered many times over and I am actually using code that seems to be working but I can't seem to get the actually data to be presented in the receiving form.
In the sending form I am select an item in a tree menu which triggers an event to open the receiving form and then pass the data. I put a break point in my receiving code and can see the data is applied to the variable. I applied that variable to text box but it does not appear on the open form.
Here is the code from the sending form. I am first checking to see if the form is open. My variable that I am passing is a string strControl.
If Application.OpenForms.OfType(Of Guidance_Info).Any() Then
Dim f1 As New Guidance_Info()
Guidance_Info.LoadGuidance_Info(strControl)
Else
Dim f1 As New Guidance_Info()
Guidance_Info.LoadGuidance_Info(strControl)
f1.Show()
End If
Here is the code from the receiving form. I first apply the variable to the table adapter, then a text box and then a message box. The only item that presents the data is the message box. Using a breakpoint I can see that the variable is being passed to the both the text box and the table adapter.
Friend Sub LoadGuidance_Info(ByVal ControlID As String)
Me._800_53_CtrlTableAdapter.FillByControl(Me.AssessGuidanceDataSet1._800_53_Ctrl,
ControlID)
Me.lblControl.Text = ControlID
MsgBox(ControlID)
End Sub
As you can see from this image the variable is receive properly:
Friend sub LoadGuidance_Info
I also tried using f1.ShowDialog() instead of f1.Show() but got the same results. The problem with the Dialog, you can't use the sending form until you close the receiving form.
Any help would be appreciated:
Your problem has nothing to do with passing data, but what you are passing it to.
You look for an open form instance but whether you find one or not, you create a New form instance, pass the data to a default form instance, then show the (New) form instance you created. In the end you have as many as 3 instances of the same form:
' first instance may be in the collection
If Application.OpenForms.OfType(Of Guidance_Info).Any() Then
...similar issue to below
Else
' create a NEW instance (#2)
Dim f1 As New Guidance_Info()
' use/create a default instance
Guidance_Info.LoadGuidance_Info(strControl)
' show #2
f1.Show()
End If
Neither #2 nor #3 can ever be the one that may be showing. Rather than just checking the collection for an instance, get it and check that (using more idiomatic naming):
Dim f1 = Application.OpenForms.OfType(Of GuidanceInfo)().FirstOrDefault
If f1 IsNot Nothing Then
' use existing
f1.LoadInfo(strControl)
Else
' create, update, show one new form instance
f1 = New GuidanceInfo()
f1.LoadInfo(strControl)
f1.Show()
End If
I am using Excel VBA. I have two user forms:
ClientInfo and ClientSearch
In ClientSearch, I search through an excel worksheet to list all clients with the same last name. From there, I pick the client I want (by highlighting the name in the list and clicking on command button cmdOpenClientInfo) and determine their ClientID (which is also in the worksheet).
I then want to pass this ClientID to the form ClientInfo in order to populate all text boxes on this form with the relevant data from the worksheet:
Coded in the ClientSearch form:
Private Sub cmdOpenClientInfo_Click()
Dim ClientID As Integer
ClientID = textSrchClientID.value
'user msgbox to check to make sure I get the correct ClientID ... and I do
msgbox(ClientID)
Me.Hide
frmClientInfo.show
Call frmClientInfo.PopulateClientInfo(ClientID) 'this is where it fails
End Sub
Coded in the ClientInfo form:
Sub PopulateClientInfo(ClientID As Integer)
'this is where I would populate the text field
End Sub
The routine always gets stuck at the
CALL frmClientInfo.PopulateClientInfo(ClientID)
In the case above, I get Run-time error '424' Object Required.
I have tried various solutions presented in this forum, but have not found a solution.
Your call to frmClientInfo.show is in Modal mode, so the next statement wont execute until the new form closes. You can try to make the call non-modal:
frmClientInfo.show Modal:=False
But this may be source of other problems. Better keep working in modal mode but pass the ClientID parameter to the form before it shows up.
1- Modify your PopulateClientInfo method of frmClientInfo like this:
Public Sub PopulateClientInfo(ClientID As Integer)
'....
'populate The fields, then:
'....
Me.Show ' <-- form shows itself after populating its fields
End Sub
2- Remove the call to frmClientInfo.show in the ClientSearch form.
You can't call a procedure in a form module from outside that module. Try this code (sorry, I didn't).
Private Sub cmdOpenClientInfo_Click()
Dim ClientID As Integer
Dim FrmInfo As frmClientInfo
ClientID = textSrchClientID.Value
'user msgbox to check to make sure I get the correct ClientID ... and I do
MsgBox (ClientID)
Me.Hide
Set FrmInfo = New frmClientInfo
With FrmInfo
.Tag = ClientID
.Show
' make this call in the FrmInfo Activate event procedure
' PopulateClientInfo(cint(Me.Tag)
End With
Unload FrmInfo
Set FrmInfo = Nothing
End Sub
I presume that you have a form which is named frmClientInfo. You can create an instance of that form with the command Set FrmInfo = New frmClientInfo. This object will not show until the Show method is invoked but you gain access to all its controls. To pass a variable to that form you can address any of them. Perhaps you have a Tbx which should show the ClientID. You can access that Tbx and set its value. The above code assigns the ClientID to the Tag property of the form itself.
The form's Activate event will occur when the Show method is invoked. That would be the moment to run the PopulateClientInfo procedure (from within the frmClientInfo module, of course), retrieving the ClientId from the Tag property.
Bear in mind that the code will continue running in the cmdOpenClientInfo_Click procedure when the ClientInfo form is closed. So, that is the time to remove that form from memory, on the one hand. On the other, the 'FrmInfo' object still exists and you could pick any information from it that you might want to use in the form which made the call. The syntax is very simple, like, FrmInfo.Textbox1.Value.
I'm trying to set up a button that does the following:
Checks to see if a form is open (and has lost focus). If so, it brings that form to the front.
If not, it opens a new instance of the form.
However, I've tried a few different methods and it will always either create a new form (if I use frm_About.visible as the check) or simply not do anything (with the following code).
Private Sub counter_aboutClick(sender As Object, e As EventArgs) Handles counter_About.Click
If Application.OpenForms().OfType(Of frm_About).Any Then
frm_About.BringToFront()
Else
Dim oAbout As frm_About
oAbout = New frm_About()
oAbout.Show()
oAbout = Nothing
End If
End Sub
I've heard that there's a bug with BringToFront in certain scenarios, am I hitting that bug?
VB.Net does a terrible thing and creates a default instance of a form (which can be referred to by its class name). This creates endless confusion and headaches - I suggest you read up on default instances (google can find a lot to read about, surely)
In this case, you have a class called frm_About as well as a default instance of that form which is also called frm_About. If you've created a new form of type frm_About then the following code
If Application.OpenForms().OfType(Of frm_About).Any Then
frm_About.BringToFront()
will search your open forms to look for a form of type frm_About and, if it finds one, will attempt to bring the default instance of frm_About to the front - note that the open form can be (an in your case is most likely) not the default instance but any instance created with New frm_About().
To find the actual instance of the form you would have to do something like :
For Each openForm In Application.OpenForms()
If TypeOf (openForm) Is frm_About Then _
CType(openForm, frm_About).BringToFront()
Next
Hey guys I have got to a head scratcher well at least for me any way. I need to find a way of opening a form with a string. I have got this ...
Dim asm = System.Reflection.Assembly.GetExecutingAssembly
Dim myTypes As Type() = asm.GetTypes()
Dim frm As Form
For Each t As Type In myTypes
If t.IsSubclassOf(GetType(System.Windows.Forms.Form)) AndAlso Me.Label4.Text = t.Name Then
frm = CType(Activator.CreateInstance(t), Form)
frm.Close()
frm.Hide()
End If
Next
But it doesn't close the program or even hide it i have no clue?
Question: "I need to find a way of opening a form with a string"
Thanks in advance.
That looks to me like you created a new form instance of that type and tried to close/hide it, but I don't see it ever being shown.
If you are trying to close an existing form, then you don't want to create a new instance using Activator.CreateInstance. Rather you need to somehow locate the existing instance of the form that is already open, and close that specific instance.
The code you posted approximates code that would create a new instance of a form by type name, then close/hide the form.
(If you wanted to close an already-open form by name, I would do:
For Each f As Form In My.Application.OpenForms
If f Is My.Forms.NameOfFormThatIWantToClose Then f.Close()
Exit For
)
But I thought you wanted to open a new form by name. If so, you will need to use reflection. This page seems to do exactly what you want.