I'm a bit confused on exactly how the architecture for a VB.NET forms app actually works.
I've noticed in others' code, lines that read a little like this:
If frmMain.someBooleanProperty Then
but, I'm a bit confused because someBooleanProperty is then defined as an instance variable (i.e., as Public someBooleanProperty As Boolean in frmMain). How is it being referenced statically to access an instance variable? Is this just bad coding practice?
For reasons of backwards compatibility, VB.NET automatically creates an instance of every Form. This instance is accessible through a global property which has the same name as the Form class itself.
More details can be found here:
Why is there a default instance of every form in VB.Net but not in C#?
Related
I'm trying to convert WinForms app into a class library - long story short the production environment I'm working in will allow our users to make changes to DLLs but not EXEs, so I'm trying to shove an entire existing app into a DLL and then just create and show an instance of the startup object/form from a second WinForms app with the goal of creating some kind of auto-update system.
I've changed the output type of the project to Class Library, added the launcher app, etc, but attempting to build the old app as a class library throws hundreds of errors, almost all of which are Reference to a non-shared member requires an object reference.
Upon inspection, these errors are appearing everywhere in the code that the startup object/form or any of its properties or methods are referenced. Since a great many things in a WinForms application naturally reference the main form... this is problematic.
Stuff like:
If DbConn = n.DbConn_.Prod Then
miParent = mainform.MiProdReq
throws the aforementioned error upon the attempt to access mainform.MiProdReq
Am I missing some simple/obvious step here?
You are referring to the default instance of the mainform type in that code. Default instances are provided by something automagically generated when building Windows Forms Application projects. Class Library projects have no such thing as default instances, so any code that tries to use them will appear to be trying to access instance members as though they were Shared.
You need to put an instance somewhere and change your code to refer to that instead. If you use a global variable, which is not ideal itself but the simplest option for where you're at, then you can just do a Find & Replace In Files to find the references you need to change.
Note that default instances are something that most experienced developers would suggest avoiding anyway. They don't exist in C# and I've never heard complaints about that, so it's hardly onerous. They were added to VB as a convenience for beginners and migrating VB6 developers who weren't used to proper OOP.
EDIT:
I haven't tested it but you may be able to use Application.OpenForms(0) to get a reference to the startup form anywhere in your library. You could, perhaps, add a module like this:
Module Module1
Private _mainform As Form1
Public ReadOnly Property mainform As mainform
Get
If _mainform Is Nothing Then
_mainform = DirectCast(Application.OpenForms(0), mainform)
End If
Return _mainform
End Get
End Property
End Module
and then your code may even just work as it is.
This question already has answers here:
Objects implicitly instantiated in vb.net?
(2 answers)
Why is there a default instance of every form in VB.Net but not in C#?
(2 answers)
Closed 7 years ago.
Short version: A class is being used without a variable of it's type being instantiated. How?
I have a huge legacy program which was converted from VB6 to VB.net.
It is compiling and many aspects work, but there is a problem related to an MDI (Multiple-Document Interface) display. I have placed other test forms under the parent MDI form, and they display correctly. The form in question does not display. (And, of course, it is the MOST important, and a most intricately complex form. I wish I could re-write it, but there is no possibility of that.)
There is a class, MDI1, which is used over 7,000 times in the code by many, many other classes. The MDI1 class is used extensively in the form which does not display. Wherever MDI1 is used, it is always referred to as simply MDI1 or Namespace.MDI1 . As far as I can tell, it is never instantiated as an object. It is as though it is a singleton, somehow, but I see nothing making it one.
The header for the class follows:
Option Strict Off
Option Explicit On
Imports VB = Microsoft.VisualBasic
Friend Class MDI1
Inherits System.Windows.Forms.Form
Dim MDI_Activated As Boolean
Public Sub New()
MyBase.New()
InitializeComponent_Renamed()
End Sub
...
Can anyone tell me what may be going on here?
Every place where it is used that I've tried to check in Visual Studio by right clicking and selecting "go to definition" takes me right back to the class definition (line 4 of the above code), and never to a variable of type
MDI1. I have searched the entire source (using both Visual Studio and grepwin outside of Visual Studio) and can find no variable instantiated with type MDI1.
I don't understand how the calls to the class are working, without a variable of that type.
Help would be greatly appreciated.
I am using Visual Studio 2010 Professional, the latest version to which I have access.
I am assuming that you are not aware of Default Form Instance in VB.NET and hence the surprise. Its a common problem since this is missing in C#.
For winforms application in VB.NET, each form has a default instance and can be referred to simply by its form name (class name). You can ofcourse create your own instances like any other class and choose not to use the default instance.
This feature is particularly useful for legacy applications that have been migrated from VB6 to VB.NET since default form instance was a norm in VB6.
You can read more about Default Form Instances here:
https://msdn.microsoft.com/en-us/library/ms233839.aspx
And
https://msdn.microsoft.com/en-us/library/aa289529(v=vs.71).aspx
Hi i'm having to learn VB.net for a new job having previously been a C# guy. I just come across an interesting feature of VB.net. I can reference objects on a second form that has not been instatiated!
So from Form1 i can get the text property of textbox1 on Form2 as follows
Dim txt As String = Form2.TextBox1.Text
Can anyone explain how this works? Are all forms instatiated at the start of the program and then their visibility is toggled throughout the program lifespan?
Forms in VB are a special case. The compiler generates a strongly-typed list of forms in the My.Forms object of the My namespace. Each form is exposed as a property My.Forms.TheNameOfTheForm. These properties always return valid instances – i.e. if a form hasn’t been instantiated before, it will when you first use the property.
So far, so good.
But Microsoft also made the brain-dead (!) decision of importing the properties from the My.Forms object by default, everywhere, and there’s nothing you can do. Superficially, this is for backwards compatibility reasons to VB6 but that’s nonsense since VB7 (.NET 1.0) didn’t have this feature, it only came later.
But just to clarify:
Are all forms instatiated at the start of the program …?
No, luckily not. They are instantiated the first time you access the property.
I'm trying to split some prior crafted code into a DLL. It's a simple logger system.
There are a few things that need to be shared with the main form in the project, so I set them up as a shared variable, but I don't use shared stuff often, and I worry it will cause variable conflicts regarding scope. I figured I would make a post here about it and see if someone can explain what I don't fully understand.
Since this is a logger it will be used a couple of places. Other DLLs that need logging may reference it through a instanced object and project reference. My main form will also have an instanced object and a reference to the logger libary.
Since one of my properties is a connection string and it's shared, does this mean that a instance of my logger class inside a DLL will have the same shared values as a instance on my main UI form? Or will the fact that the instance is inside of a DLL provide the scope boundary I need? I'm hoping it does..
I mainly worry that I might want to log using two different connection strings down the road.
(I hope my question makes sense. If it doesn't, post comments and I'll try to clarify.)
No, the fact that the instance is in a DLL does not provide the scope boundary you need. If the class or members in the DLL were declared static they would be shared and you could run into problems. So, just don't declare them static and be sure to create new instances of the object(s) when you consume them and you should be ok.
I am from a c# background and am converting a vb.net windows forms app to c#.
I have a windows form called associateForm.
In code the developer references associate form like so:-
Private Sub NotifyIcon1_MouseClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles EMS.MouseDoubleClick
If e.Button = Windows.Forms.MouseButtons.Left Then
If associateForm.WindowState = FormWindowState.Normal And associateForm.Visible = True Then
associateForm.WindowState = FormWindowState.Minimized
Else
associateForm.WindowState = FormWindowState.Normal
End If
associateForm.Show()
associateForm.Focus()
'bring to front of other windows
associateForm.Activate()
End If
End Sub
But the thing is that associateForm is not instantiated within the class where the method is being executed. Nor is the class static. Nor does there seem to be an instance of the class anywhere in code. Can anyone shine any light on why this seems to work but when i try this in C# it is not having any of it.
VB.Net for .Net 2.0 and later has something called default form instances. When you define a form, you get an automatic instance of the form with the same name as the type.
Several things are wrong with the previous comments. Joel's is basically the correct answer, with one small caveat:
When you define a form, you get an automatic instance of the form with the same name as the type.
You actually only get the instance when you call it. Before that, no default instance is created. Thus, instance creation is deferred until the time of usage.
Using the name of the form as an instance is actually a shortcut to My.Forms.Formname, which is a compiler-generated list of properties for all forms. These properties are responsible for the object creation. It is unfortunate that Microsoft has decided to make these properties implicitly available at global scope (hence the OP's question).
This feature exists because VB.NET emulates the VB6 method of being able to refer to a default instance of a form through it's name.
Well. While this feature is inspired by previous versions of VB, it's not a direct descended. VB 7 didn't have it. Rather, it was re-introduced with VB 8 (= VB 2005).
A really really stupid "feature"
Actually, it's a dead useful feature that plays very well with VB's RAD development philosophy. As mentioned above, it's unfortunate that such a loose scoping is employed. But other than that, I'd be very interested in hearing what's so “stupid” about this feature.
Joel is correct. This feature exists because VB.NET emulates the VB6 method of being able to refer to a default instance of a form through it's name.
When you convert this to C# you need to provide global access to a a single instance named associateForm. There is a chance that something is preserved in between calls to this form. After you successfully gotten it working this way. Then you can refactor the software and test to see if a local instantiation will work the same.
I can't answer your question directly, but...
I'm guessing you're converting from VB.Net to C# manually - have you tried using an automatic convertor instead?