How to access this variable? - vb.net

I'm new to VB and I'm currently migrating a vb6 app I did not write to .net and I'm struggling with this error,
If TypeOf Application.OpenForms.Item(i) Is frmAddChangeDelete Then
'UPGRADE_ISSUE: Control ctrlAddChangeDelete1 could not be resolved because it was within the generic namespace Form. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="084D22AD-ECB1-400F-B4C7-418ECEC5E36E"'
If **Application.OpenForms.Item(i).ctrlAddChangeDelete1.ParentFormNumber = intFormNumber** Then
If Application.OpenForms.Item(i).Text = "Add Proofed Expense Items" Then
boolAddProofed = True
Exit For
ctrlAddChangeDelete1 is supposedly calling the friend class ctrlAddChangeDelete from a separate VB file, so I'm not sure why it's saying that
"'ctrlAddChangeDelete1' is not a member of 'System.Windows.Forms.Form'."
Any help is appreciated, thank you !

Application.OpenForms is a collection not strongly typed.
When you reference elements there you get back a generic Form.
In a generic Form there is no control named ctrlAddChangeDelete1
If you have a form derived class named frmAddChangeDelete and this class has a control named ctrlAddChangeDelete1 then you need to cast the reference stored in the OpenForms collection to your specific form class before trying to reference that control.
Moreover, to access that control from external code, you should also have the Modifiers property set to Public instead of the default Internal. Otherwise you will not be able to access the control from any code external to the class.
To retrieve correctly your form you can write
Dim delForm = Application.OpenForms.
OfType(Of frmAddChangeDelete)
FirstOrDefault()
If delForm Is Nothing Then
' No form of type frmAddChangeDelete is present in the collection
' write here your message and exit ?
Else
' Now you can use delForm without searching again in the collection
......
The code above uses the IEnumerable.OfType extension and this requires the Imports System.Linq.
If you don't want to use this then you can always use the TryCast operator to get the reference to the correct class
' Still you need a for loop up ^^^^ before these lines
Dim delForm = TryCast(Application.OpenForms(i), frmAddChangeDelete)
if delForm Is Nothing then
....
else
....

Related

How to Build a List of Form Controls Before the Form is Loaded

I’m new to OOP and VB.NET, so please bear with me.
In VB.Net I currently have working code that defines, for each form, significant information about selected controls on the form.
I have defined in a public class:
Public Class FormFld
Public Property ScrField As Control ' A control on the form
Public Property DbField As String ' Its corresponding field name in the database
… ' Other info about the control or its database field
End Class
When each form loads, I create a list of FormFlds for the form’s selected controls:
At the start of each form
ReadOnly FormFlds As New List(Of FormFld)()
and in the form’s Load routine
FormFlds.Add(New FormFld With {.ScrField = Control1Name, .DbField = "Field1Name", …})
FormFlds.Add(New FormFld With {.ScrField = Control2Name, .DbField = "Field2Name", …})
…
This technique has worked well to easily loop through the selected fields and, on input, populate those fields from the database, or, on output, write those field values to the database.
With this implementation, however, the list must be built every single time the form is loaded. I’m wondering if the setup of the list can be done only once, during program initialization, before the forms are loaded.
Here’s the latest that I have tried.
In Class1:
Public Class indiv
Public FormFlds As List(Of FormFld)() ' The list for the frmIndividual form
End Class
In Module1, I attempt defining the FormFlds for the eventual form frmIndividual, to be saved as Indiv.FormFlds. I’d like the form name (f) and the list owner (owner) to be defineable so I can easily change those for each form.
Dim owner As New indiv
Dim f As FrmIndividual
owner.FormFlds.Add(New FormFld With {.ScrField = f.TxtKey, .DbField = "Sort_Key", …})
In Visual Studio, the third line shows error “BC30456: 'Add' is not a member of 'List(Of FormFld)()”.
Wondering if the problem might be due to not having an actual form FrmIndividual created yet, I tried changing the second line to
Dim f As New FrmIndividual
but it didn’t change anything.
I’m using VS 2022, v17.2.1. If there’s more info you need, please let me know.
The reason that you're told there's no Add method is because arrays have no Add method and you have an array. Here:
ReadOnly FormFlds As New List(Of FormFld)()
You are using the New keyword to invoke a constructor, so the parentheses at the end are for the argument list for that method call. Here:
Public FormFlds As List(Of FormFld)()
there's no New keyword so there's no constructor, so the parentheses at the end indicate that the field is an array type. That code is functionally equivalent to this:
Public FormFlds() As List(Of FormFld)
When you get that field you're getting a reference to an array of List(Of FormFld), not just a single List(Of FormFld) object. Of course, the field is initially Nothing anyway, so you'd have to assign something to it first to be able to use it.
By the way, the error message was already telling you what the issue was:
'Add' is not a member of 'List(Of FormFld)()`
It is telling you that Add is not a member of array of List(Of FormFld), which it's obviously not.

Add Public Methods to a Userform Module in VBA

Is it possible to call a public sub located in a UserForm from a Class Module? I want to put a callback in the Form Module but I can't seem to get it to expose.
Is this a fundamental limitation of UserForms in VBA?
It is exposed inside the UserForm Code Module, I can see it in the intelisense for the Me object, but I can't seem to access it from outside the Form Module.
The real answer to my question is to have a better understanding of UserForms and since I could not find a good reference for that I thought I would answer my own question to share my learnings.
Thanks to #Dick Kusleika for the key insight!
First of all, this is not a UserForm:
It is no more a Form than a Class Module is a variable.
UserForm1 is a Class Module with a GUI and with the following default, inherited properties
These properties are like a standard Interface that is common to all Form Class Modules and therefore instances. The Name property is in parentheses because it is not the name of the object, it is the name of the the Type that is used to declare variables to instantiate the particular Form Class.
More properties and methods can be added by the user at design time and this is done in exactly the same way as a Class Module.
For example, in a Form Module...
Option Explicit
Dim mName As String
Property Let instName(n As String)
mName = n
End Property
Property Get instName() As String
If Len(mName) = 0 Then mName = Me.Name
instName = mName
End Property
In this example, the Form Class Name is used as the default Instance Name.
When you add Controls to the form, its like graphically adding
Public WithEvents controlName As MSForms.ControlType
...in a Class Module.
The Methods inherited in the standard interface include one called Show.
You can create an instance of a form using UserForm1.Show and this is very confusing and misleading. To me it implies that you are showing the Object called UserForm1 but you are not. I don't know why you would want to use this method because, apart from being confusing, it does not deliver any direct reference to the object created. Its a bit like Dim v as New Type only worse, because there is no referencing variable.
You can instantiate a Form Class in exactly the same way you can a Custom Class object and then use the show method to deploy it...
Dim f As UserForm1
Set f = New UserForm1
f.Show
For me, this is the preferred method.
You can add custom properties and controls to the UserForm1 Class and you can give it a meaningful name when creating it, but you can also reference it using the standard UserForm interface.
For example
'In a Class Module
Dim mForm as UserForm1
Property let Form(f as MSForms.UserForm)
Set mForm = f
End Property
For me, after understanding the above, all of my confusion about UserForms and my frustration at not being able to find a decent reference disappears. I just treat them as Class Modules and its fine.
The only difference between a Userform and Class Module is that a Userform has a UI element that a Class Module doesn't. So a Userform is just a special type of Class Module. That means that Public Subs inside a Userform behave just as they do in any other class - as a method of the class.
To access a Public Sub inside a class module (such as a userform), you need to instantiate the class, then call the method.
Dim uf1 As UserForm1
Set uf1 = New UserForm1
Uf1.MyPublicSub

Late Binding to a form's public variables

I have 20+ MDI forms with consistently named Public variables. When the child form closes a method on the MDI Parent is called passing Me as a generic form type. How can I access the public variables by name via the Form reference? I only need to read the variables. Of course the Variables() method does not exist...
Public Sub CleanupForm(ByVal frm As Form)
Dim sTable_Name As String = frm.Variables("TABLE_NAME") ' Public at form level
Dim cLock As clsRecLocks
cLock = frm.Variables("Rec_Lock")
cLock.DeleteThisLock()
'..
I've seen some posts on similar requests but most start out with "don't do it that way..." then go off in the weeds not answering the question. I concede it is poor design. I can't change all the calling forms in the short term so I need to use this approach.
VS2010, VB.Net, Win Forms, .Net 2.0
I was able to get to a simple variable using CallByName:
Try
Dim s As String = CallByName(frm, "TABLE_NAME", CallType.Get)
Stop
Catch ex As Exception
MsgBox(ex.Message)
End Try
On to the class object. Perhaps I can add a default Get for the class that returns the ID I need.
Default property won't work as the Locks object was not declared Public - at least for the CallByName() approach.
Can Reflection get to form level variables not declared Public? Seems like a security issue, but...
Can I get a "Parent" reference in the instantiated Locks class? i.e. A reference to the form that established the Locks object? I can change the clsRecLocks() class.
I found a property I could get to that told me the form was "read-only" and I can use that tidbit to delete the correct (or more correct - still not 100%) lock record. So the bug is 90% fixed. I think I need update all the forms with code that records the info I need to get to 100%.
Thanks to all!
Poor design but you can do this:
Public Sub CleanupForm(ByVal frm As Form)
Dim frmTest as object = frm
? = frmTest.TABLE_NAME
? = frmTest.Rec_Lock
End Sub
This will compile and if the variables exist, it will return them but if not, you get an error.
Converting to an interface after the fact is not that hard, you should do it now rather than later.

Error when trying to access a textbox on a User Control assigned to a public variable - vb.net

I created two user controls with different user interfaces. Depending on a selection the user makes, one of these interfaces will be used in my class. Since I don't know until after the user makes a selection, I cannot declare the user control ahead of time so I created a public variable to later assign the correct user control to.
The error occurs when I try to access a control (textbox) on the user control. However, if I declare the user control without assigning it to the public variable, then I don't get an error. Also, if I were to assign the user control to the public variable as its being declared then I don't get an error either. I really do need to be able to pick between the two user controls though. I don't know what to do. Am I missing something? I appreciate any help.
Public Class VesselData
Public RCAVesselData
Public AOLVesselData
Public Sub New()
If Main.UserSelectedModule = "Arrival on Location" Then
OperatorView = New AOLVesselData 'User Control 1
ElseIf Main.UserSelectedModule = "Running Conventional Anchors" Then
OperatorView = New RCAVesselData 'User Control 2
End If
OperatorView.txtDistanceToFairlead.text = "A" 'THROWS MissingMemberException - Public member 'txtDistanceToFairlead' on type 'AOLVesselData' not found.
Dim Test as New AOLVesselData
Test.txtDistanceToFairlead.text = "A" 'DOES NOT THROW EXCEPTION
End Sub
The problem is that you are accessing a member that doesn't exist. From the code you have posted, of the AOLVesselData and RCAVesselData classes, it looks like the RCAVesselData class does not have a txtDistanceToFairlead member.
If you have a common set of methods/properties you expect both user controls to expose, refactor them into an Interface and have both user controls implement that Interface. That will make it easy to use them interchangeably.
Try using Shared instead of Public when you declare OperatorView. And, like tcarvin said, you might want to turn "Explicit" on (project compile options) or use "Option Explicit".

Get Reference to an object from external application

Hi all
I have handle of a usercontrol on external application in vb.net.
I know class type of that user control.
I want to get refrence to that object to check some properties of that object.
Is it possible and how?
thanks
I hope I do understand your question right...
You may try to insert a reference to your library (I assume your userControl is in this library). As a prerequisite this external application must be written in .Net or have some kind auf COM interface!
Then you may try to access the userControl class by
NAMESPACE.CLASS myReference = new NAMESPACE.CLASS();
hth
You can get some info by using interop, with some functions like GetWindowText and SendMessage, however this won't allow you to get all properties, and won't work on every type of application (WPF or Java come to mind).
The Control Class has a method FromHandle:
Dim myCtrl As knownType = Control.FromHandle(knownHandle)
'then get the known property using Reflection
Dim oProp As System.Reflection.PropertyInfo = myCtrl.GetType.GetProperty("KnownProperty")
Dim oValue As Object = oProp.GetValue(myCtrl, Nothing)
'or directly:
Dim oValueD as Object = myCtrl.knownProperty
I don't know if it works between processes.