Modal Dialogs and Forms
I changed some of my forms to modal by using...
After I did this I noticed some weird behavior on the child form.
It seemed to retain some of it's lables and selection values after it was closed then reopened via the main form. It was almost like I as using form.hide insted of form.close. The Arrays on the form were not getting cleared either.
I was simply wanting to make my forms modal (where they are the only form on the screen that's allowed to have focus). But it seems iv'e got some extra stuff happening that really messing things up for me. Is there a way to get modal forms without these 'side effects'?
I use modal forms very often and never got that type of problem.
Put a MessageBox in the FormClosing event of the form. If there are instances where it is not called, then you have code somewhere that hides the form.
Search in all the solution (Ctrl-Shif-F) for "Hide" and "Visible = False" (with the spaces), just to make sure that you do not have forgotten code to that effect somewhere.
It's really weird, because when I switch back to non modal. Everythings fine. I've searched the entire solution and nothing jumped out at me, i'll have another look in the morning when i'm fresh.
I indeed use modal forms very often and never had your problem. But I thought that it is probably because most of my modal boxes are used only for display or to enable the user to select something or set options.
So I decided to test the thing, and oh, to my great surprise, you are right. Could not come to understand why however.
It made no sense. Scratched my head, I am bald now.
Then I saw something strange:
Where in **** did I call the constructor on that form? Nowhere.
Tried it the right way:
"Et voilà" as we say in French. Problème réglé... problem solved.
Dim frm2 As New Form2
It seems as if Visual Studio creates a Public form with the same name as the class. The compiler probably generates something like Public Form2 as New Form2 somewhere. That is what the VB6 compiler did. We did not have to implicitely declare a Form before using it, we just "called the class".
Because it caused problems (what you just lived is a good example), they decided to do otherwise when they designed .NET. I remember very well one of the first things I learned when I switched from VB6 to VB.NET, and this was the surprise to learn that I had to declare a variable before I could use a form.
I thus took the habit of declaring form variables. As most professional programmers, I had problems with the old system, so I was glad that they had solved those. Declaring a variable myself gives me more control and prevents bugs.
But a lot of amateurs did not like to have to work for something that came free in the older version. They could not see the tremendous advantages of using .NET and the thousands of lines of code it could save. They saw only the few extra lines they had to write compared to the old. Microsoft had problems making them switch to .NET, and at some point, some stupid Microsoft guy, probably from the marketing department, decided to bring back those simple things, specially in version 2005, when they introduced a few "make it easier" features such as My.
I suppose that at that time, they decided to bring back the old way to use forms. And because I was used to declaring and instanciating a variable for my forms, I did not see that one pass.
And it seems that as it did in VB6, this still causes problems. I hope you did not lose too much sleep on that one.
I checked in C#, and that behaviour is not acceptable, you have to declare a variable before using a form.
So, the morale is: always declare a variable for your forms. When you lose the variable or reinstanciate another form on it (call New again for the same variable), you lose the form, for good.
Because you take control instead of leaving the control to Microsoft, only to save one line of code here and there.
Once again, very nice work. I would have never figured that out. I didn't loose any sleep, I simply switched them back to non-modal and moved forward. I wasn't goning to screw around with somthing I could not understand.
So your basically saying I need to decalre a new instance of whatever form I'm wanting to call modally? Then using the instance, call the form.
I'm not sure I totally understand why you would need to do this with a modal form and not with a nonmodal form. But atleast I know how to fix the problem.
You should work with instances whenever you work with forms, not only for modal forms.
Since 2002 (arrival of .NET), I had never seen code that used the class directly for a Form. The sample code in MSDN always create instances, including the page that shows how to use the Form Class and the one for ShowDialog.
You might have got the trick in a Newsgroup or a forum somewhere. Always consider what you get from forums as suspect... even my own code. Between the Visual Studio documentation and forums, 98% of the time, the documentation is better. The 2% where a post in a forums is better is probably one of my good posts .
You cannot understand why there is a difference between a modal and non modal form with the syntax you used, neither do I, because if I am right, this trick that they added to VB that enables you to use forms without an instance generates hidden code. Hidden things are hard to understand. I have looked, and it is does not seem to be documented, probably because the people that are prone to use this method would not understand the documentation anyway.
I can tell that you are passed that point in you development as a programmer, since you seem to understand that doing things the right way is always better , in the long run, than doing it the fast and easy way.
For me it's 98% usefull information comming from your posts and 2% of the time having to dig deeper to solve my problem.
So the lesson of the day is always use an instance to call a form.
' Old Way
' New Way
Private Sub cmdMeteredProd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdMeteredProd.Click
' CMD Metered Prododuction
Private Sub cmdMeteredProd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdMeteredProd.Click
' CMD Metered Prododuction
Dim MeteredProductionForm As New frmMeterGroupProduction
Last edited by rrjii2000; 07-19-2010 at 09:13 PM.
New is effectively the way to go.
However, just to be finicky, your naming does not follow the conventions. Some people see conventions as a useless pain, but in practice, they make the code easier to understand, and thus, to debug and maintain later.
The conventions is that you use a 3 letters lowcase prefix for variables. Classes have names that Starts with uppercase (see the next section of the discussion).
Thus, I would rename your stuff so that the declaration is
Dim frmMeterGroupProduction As New MeteredProductionForm
I would then match the 2 names with either of the followings:
Dim frmMeterGroupProduction As New MeteredGroupProductionForm
Dim frmMeterProduction As New MeteredProductionForm
Matching both names makes it easier to see which form is represented by the variable. It would also help if you eventually make another form with a similar name.
And another change, but this is a question of preference:
Dim frmMeterProduction As New FormMeteredProduction
I prefer to always use prefixes. Thus, when you are looking for something, it is easier to find. Just type Form... and IntelliSense automatically lists all the forms. If Form is at the end, you have to remember the exact name of the form, IntelliSense cannot help you to find it.
It is easy to understand that you used the 3 letters prefix frm for your forms, because you also use a 3 letters prefix such as txt for a TextBox control. Since both forms and controls are given names through the (Name) property in the Properties window, one tends to think that they do the same thing.
But it is not the case.
When you name a control, the form designer creates a variable with a declaration like the following (hidden in the designer.vb file that is created along each forms):
Dim txtName As TextBox
So, a Textbox is a variable. The convention is a 3 letters prefix.
When you name a form however, the generated code is a class, as you can see on the first line of your standard form code file:
Class Form FormMeteredProduction
So, a form is a class, and does not follow the same naming convention.
When you use the class, you create a variable, so, this is where you use frm...
Hope its clear.
So the form files in my project window don't necessarily need the frm prefix. You're saying I should actually save the frm prefix for use when I call an instance of the form. However controls are different and should always have the corresponding prefix.
I've always been a stickler when it comes to prefixing my varables. Years ago I purchased some keystone learning videos for VB3 and they really inforced using prefixes, so it's become a vital part of my development.
In my previous example I decided to simply remove the 'frm' prefix and add a 'Form' suffix to the end for all instances of my forms. I might change them to something different when I get time. My project has 23 forms at this point so it will take some time.
Do you use a prefix for your class files as well? Because those are the only elements in my project that don't have a prefix of some sort.
No, form files do not need the prefix. You have an icon that shows that they are forms, and that icon is better than a prefix. Visual Studio actually looks into the code and put that icon only when the code is the code for a form.
Personnally, I go one step further. Many people do not know that you can actually create folders in a project. The thing is under the context menu (right click) of the project. You can create a Form folder and drag all your forms into that folder. I do that in all my applications that have more than 2 or 3 forms.
I also do the same for classes, so I do not prefix the class files as I did in the old VB. I find that having a Folder for each different thing (Classes, Forms, Modules, Controls) is a lot better than using prefixes. In application that have a big number of forms, I might also have many folders for different types of forms.
So, classes do not have prefixes. Which one would you use. There are over 7000 classes in the framework alone. The only time I use a prefix for a class is Form... for my forms, only because I consider a Form to be a special type of class. The other classes have a straight name, just as Microsoft do.
As for renaming your stuff, it is not really a big job. Simply open the file, right click on anything that is yours (class name, module name, variable, constant) and select Rename. Visual Studio is very good at that. Rename is not a simple Edit...Replace. Even if you have variables with the same name in different places, it will only make the change for references to that variable. The only drawback to that Rename function is that it won't make the replacement in comments.
As for prefixes in general, most programmers have followed Microsoft clue and have stopped using them except for special things such as controls and forms.
For any other type of variables, prefixes have become useless and simply clutter the code. Compared to VB3 that had only about 60 classes, .NET has over 7000. Prefixes become absurd when there are so many types of objects.
In VB3, prefixes were usually used to more easily identify the type of a variable. Many were also still printing their code at the time, so prefixes helped to understand the printout.
Nobody prints its code anymore, and the new feature of repeating the declaration in a tooltip when you hold the cursor over a variable is a lot better than a prefix.
Give me "str", and I will wonder if it is a String, a Stream, a StringBuilder, StreamWriter or any of the 100 or so classes whose name begins with str? You would have to create a 60 pages document to make a record of your prefixes in order to be constant with your naming conventions.
Give me the declaration (the tooltip) and the type is clearly stated.
Why should it be different for controls and forms? As a tool to help you. Other variables tends to be declared locally, so it is easy to remember the name of a constant when you are working in a procedure.
Howeven, a control can be used in dozens of procedures. Having to switch to the designer and then back into the code when you need to retrieve a prefix is cumbersome. Simply typing txt... brings you the list of TextBoxes in the form. It is a lot faster.
The folder tip is a great ideas, however when I move move all my files into folders, I get warnings on all my forms (on the class declaration line) that says 'Namespace does not coorespond to file location, should be windowsapplication1.forms.mg' Where Forms > MG are new sub folders in my project. How should I address this?
I have added some namespace code and it seems to fix the problem.
I haven't done this on all my forms yet, as I noticed it was a warning from 'resharper' (a 3rd party control) not from VB. So I think its more of a housekeeping issure rather than a major issue.
'form class here
I suspect that you created the folder outside of the project, so the default namespace for the project did not apply anymore. Maybe you moved the Forms from the application to a dll or under the Solution.
Your folder should be under the project tree. In the accompanying screen shot, JBFlow is the application and contains the Form folder. JBLib is a dll.
I have discovered another issue since switching to form instances. Some of my forms would retreve data from a textbox or even a collection that was being used on other forms.
This no longer works, and I'm not sure how to fix it.
txtMGRef.Text = frmMeterGRP.txtRef.Text
txtWellName.Text = frmMeterGRP.txtWellName.Text
txtGroupName.Text = frmMeterGRP.txtGroupName.Text
txtUID.Text = frmMeterGRP.txtUniversalID.Text
I have also abandened the folder idea untill I get everything else fixed.
Last edited by rrjii2000; 07-20-2010 at 03:59 PM.
Yes that needs just a little more work. As I told you previously, that little extra work is worth it in debugging and maintenance time.
The main difference between the instance you create yourself and the instance that was created by the framework previously, is that the framework needed to create a Public variable in order for you to be able to use it from anywhere (that also means that a bug could come from anywhere in the application, a nightmare).
Your own instance is a variable that works the same way as any other variable. You need to treat it the same way you treat other variables. The procedure that retrieves the information from your TextBoxes needs to see your variable.
The best way to do that, when possible, is to pass the form as a parameter to the procedure:
Pass your variable to the Sub when you call it, and the code will work as it did before.
Public Sub YourSub (frmMeterGRP As YourFormClass)
This is not always possible however. The sequence of calls between many methods could prevent you from being able to do so. If the code is in an event, then you are definitively out of luck, because you cannot add a parameter to an event.
In such a case, simply declare the instance variable in the Declarations section of the Form/Module/Class in which you use it. It will then become visible in the whole Form/Module/Class. It is not as desirable as a parameter however, because then, a bug could come from anywhere in the Form/Module/Class. When you work with parameters, only the methods that receive the instance can use it. You thus have a lot less code to cover in order to find where the problem is.
I hope this is clear.
Last Post: 01-17-2006, 09:19 AM
Last Post: 01-16-2006, 05:04 AM
Last Post: 10-21-2002, 05:42 AM
By Todd B in forum vb.announcements
Last Post: 06-15-2000, 01:12 AM
By Steve in forum VB Classic
Last Post: 04-06-2000, 05:24 PM
-- Android Development Center
-- Cloud Development Project Center
-- HTML5 Development Center
-- Windows Mobile Development Center