If you've read any of my previous posts, you may know that I am working on a project that reads in lines from an input file and parses each line as it is read. I've got that working great, thanks to the your help. But I've run into another problem.
As the program reads each line from the input file, it creates a tab page and lists of labels and textboxes. Some of these files have hundreds of lines and I end up with hundreds of tab pages.
I want to make it so that when another file is opened, it deletes all of the previous tab pages and other controls. Is there a way to easily clear the form of all controls and start over again?
This is completly off the top of my head, so expect to change it a bit. It just runs through removing the first tab until the tab control is empty of pages. For general usage, just use the MyTabThing.TabPages namespace to remove/add things.
Code:
Do Until MyTabThing.TabPages.Count = 0
MyTabThing.TabPages.RemoveAt(0)
Loop
Im not at work (.net) but if you just use your namespace help thing (just put the . ) then you should get a list of all the possible functions. You may have one that looks like this:
Me.TabControl1.TabPages.Clear
See if you can work it out from the descriptions that are given, thats what I do.
Well the Clear method seems to do the same as the Remove. I have a large file that translates into about 360 tab pages. Either way, the program crashes when it tries to clear this many tab pages. I get the error
---------------------------
An unhandled exception of type 'System.ComponentModel.Win32Exception' occurred in system.windows.forms.dll
~ if a post is resolved, please mark it as [Resolved] protected string get_Signature(){return Censored;} [vbcode][php] please use code tags when posting any code [/php][/vbcode]
You must be doing something else that is affecting it.
I don't know what. Basically, this part just checks if an input file has been previously opened, and if so, remove the tab pages so the next file can be parsed and displayed.
Here is a cut and paste of that area of the program:
Code:
If Me.TabControl1.TabPages.Count > 0 Then
For Each Tab In TabControl1.TabPages
TabControl1.TabPages.Clear()
Next
End If
Line by line:
Code:
If Me.TabControl1.TabPages.Count > 0 Then
If Me.TabControl1.TabPages.Count > 0 then I know that a file has been opened previously and I need to get rid of all the old tab pages.
If Me.TabControl1.TabPages.Count = 0 then I know that I can skip this and pop up an OpenFileDialog box to open a window. All of that works fine.
Code:
For Each Tab In TabControl1.TabPages
TabControl1.TabPages.Clear()
Go through each tab page and clear it from TabControl1
I've tried some other files with this and if they are any larger than 100 lines (tabpages) then it crashes. In fact, the program crashes after removing about 100 tab pages. Then I always get the error that I've shown in a previous reply, that "window handle" error.
I thought I figured out the problem. I had the clear() method in a loop. From the example given below, I saw I didn't need to do that, so I changed it to:
Code:
If Me.TabControl1.TabPages.Count > 0 Then
Me.TabControl1.TabPages.Clear()
End If
Still, I am always getting this error.
An unhandled exception of type 'System.ComponentModel.Win32Exception' occurred in system.windows.forms.dll
Why do you want/need SO many tabpages? Can't you load them in groups of twenty or something of that nature? Is a user going to actually work with 300 tabs at a time?
A window handle is sort of an identifier to the OS that allows a 'window' (could be a form or control) to receive messages. Its like the location in memory to send the messages to. Thats not the best description but should give you the idea.
I don't think the problem is just simply a product of adding or removing too many tabs though. This runs fine for me and doesn't even take more than a second:
VB Code:
For cnt As Integer = 1 To 360
TabControl1.TabPages.Add(New TabPage)
Next
MsgBox(TabControl1.TabPages.Count)
TabControl1.TabPages.Clear()
Which means the problem has to be some smaller detail. Try posting more of your code and maybe the problem will be visible.
Last edited by Edneeis; Nov 25th, 2003 at 03:21 PM.
What my program is doing is taking a batch file that an insurance company would transmit to an agency branch. It may have 7 to 10 transactions in each file (a transaction might be an insurance application, or a claim, etc). If you've ever filled out an insurance application, you may remember that there are a lot of little checkboxes and fields to fill out. The standards group these into, on average, groups of 20 or so and assigns each group a header. There are ususally about 30-50 groups per transaction. This file is transmitted as one long text string.
My program takes this string and chops it up into its individual fields and displays them with a label telling the user what each field is. We mainly use it to find errors in the file so we need to display everything so that we don't miss anything. I've got everything working great except this clear function.
My users want to say, "Alright, there is a problem in this file. Let's see if the same problem exists in this other file." At this point, they want to open another file and see its contents. Without the clear function, my program just appends the new file to the end of the old file (starts creating tab pages where it left off).
I have attached all of my code from my main form. I have a File menu with Open as the only option. All of this runs when Open is clicked.
BTW, if anyone knows of a better way to sort through the headers, please let me know.
You may have to have at least 1 tab in the tab control at the least (this is a theory). And yes, sorry, you dont use the .clear method in that loop, just call it the once.
I did have the loop commented out around the clear method. It was in an if statement though I've since taken that out as well. I'm still having the same problem.
That was a god awfully long select statement. Even though I wrote it, it still scared me.
So I've made some changes, such as getting rid of the if statement and letting the clear method run the first time a file is opened. I also followed Edneeis's suggestion to put that select case into an array. I wanted to do that originally, but I couldn't figure out how to get the correct .dat file. Edneeis showed me just how obvious it was.
So anyway, attached is the zip file of my project along with all 208 .dat files and a sample input file, ROBIN.FIX. The program expects the .dat files to be in c:\al3parser\dat, so you will need to make sure they are there if you go to run it. The way to reproduce the problem is to open ROBIN.FIX then, once it is fully loaded, click File->Open again. It should crash on the clear method (at least it does for me).
It also crashes here (its not just you). Ive tried various things, it appears to be the number of controls in total, not just the tabs.
Ive added 1000 empty tabs, and removed them, it worked fine.
Ive got a few suggestions (not this issue) to make things a bit quicker.
When I get home Ill do a little update for you and re-attach here.
I believe the problem stems from the tabpages being removed but not disposing properly of all of the dynamica controls on the tabs. I fixed the problem by looping through and removing then disposing of the controls on the tabs then the tabs themselves. This worked and I also changed a couple other things; Made the list of data files and their location dynamic by using an ap.config file, using Suspend/ResumeLayout which holds off on painting controls and speeds up the adding and removing, added a spalsh type screen that tells the user to wait. Refer to the comments in code for anything else especially the clean up on form_closing.
The file was too large to attach, at first, so I didn't include the dat files in the zip.
(not using the authror's code but mine i posted in the thread earlier)... I added 1000 tab pages with 20 textboxes on each. So that's 20,000 controls. (on a machine with only 512mb)
Originally posted by Edneeis I believe the problem stems from the tabpages being removed but not disposing properly of all of the dynamica controls on the tabs.
So, you're thinking the Tabpage Components dispose is not removing all the controls, or all the TabControls' compent container dispose?
Yes I believe it is a problem with the GC or a matter of timing really. Since the error is related to the a Windows Handle I think that it may be something along the lines of it trying to move on to the next line of code but being kind of hung still disposing objects. The error happens if you loop and remove but if you loop, remove and dispose it doesn't. Its very odd. I couldn't reproduce the error in a sample project by just looping and testing but I didn't really see anything untoward in his code.
I'm not sure why it happens but it happens on the removal of the 101st tabpage. Maybe its related to that specific page? Nevermind it must be related to the amount of memory used. If you dispose the tabs but not the controls then it crashes around 200.
Also he has about 60 controls on each tab and 359 tabs, which is 21,540 controls about the same range you used.
Last edited by Edneeis; Nov 26th, 2003 at 01:40 PM.
Wow! That's awesome. It just goes to show that I have a lot to learn.
I'm wondering though, might it just be quicker to quit the program and/or start another one. The sample input file I gave took just about 20 secs to clear. And that was only 100K. Some of the input files we'll be dealing with are upwards of 3Meg. They didn't want to have to close the first one and then start the program again, but if I show them that this is the best that can be done, I'm sure they'll go for it.
This has been very educational for me, even if we end up not using the stuff you guys added. I really appreciate the help and the quickness.
Well I think you'll definately want to clean up the previous file, if you want to cut down the waiting then you could start a new instance of the form (probably convert it to an mdi format) and let the other close in the background. The thing I fear, which goes along the lines of the code I added to the form_closing event is that the gc is not going to properly clean up for you and thus you will develop a memory leak. Which especially if you are opening 3meg files will be a very bad thing.
Sorry for the double post, but I have some questions, Edneeis.
A couple of times you added:
VB Code:
Me.Cursor = Cursors.WaitCursor
and also:
VB Code:
Me.Cursor = Cursors.Default
What does this mean/do?
You moved the header array to app.config. This is an xml file, correct? It will be a seperate file when compiled? Does it have to be co-located in the same directory?
To access the .dat files you use:
VB Code:
IO.Path.Combine(datpath, Header & ".dat")
Is there someway to use this if the user decides to install it in another directory when they run Setup.exe?
Finally, the way you have the Form1_closing routine written (not seeminly tied with any event), when and how is it executed?
Well done on the replies people, youve alll added the stuff that I was going to do . Saved me the time anyway. I added a counter in the loop and it actually loaded about 8000 controls in total, + the tabs. I dunno if this has been fixed, but there was a line of code that said
TabControl.Controls.Add(newtab) (or something liek that)
it would read better as
TabControl.Tabs.AddTab(newtab)
I have no idea if it has any difference on performance, other then saves casting it later.
Im intrested in the result of what causes the error, I got it on a 1.8 with 512 mem. If I have time, Ill try it on my 2.8 at home, that shouldnt have any issues with memory
I dont think its a timing issue. I created a function that removed 10 tabs at a time. then I ran that manually from a button, when it got down to 280 ish tabs left, it crashed.
Originally posted by shadowfyre Sorry for the double post, but I have some questions, Edneeis.
A couple of times you added:
VB Code:
Me.Cursor = Cursors.WaitCursor
and also:
VB Code:
Me.Cursor = Cursors.Default
What does this mean/do?
This changes the cursor to the hourglass and back to notify the user that it is working.
You moved the header array to app.config. This is an xml file, correct? It will be a seperate file when compiled? Does it have to be co-located in the same directory?
It is a config file which has the same name as the exe and must be in the same folder as the exe but yes it is an xml file. Yes it stays seperate when compiled which is the main reason I put those things there. That way if you move the dat files or edit the list of data file names you don't have to recompile, just change it in the config file.
To access the .dat files you use:
VB Code:
IO.Path.Combine(datpath, Header & ".dat")
Is there someway to use this if the user decides to install it in another directory when they run Setup.exe?
Yes since it pulls the path from the config file it can be changed on install or at any point thereafter.
Finally, the way you have the Form1_closing routine written (not seeminly tied with any event), when and how is it executed?
Actually it is an event, the closing event which fires during the closing of the form but before it is done closing.