How to dispose of a Forms.Timer on the Compact Framework - compact-framework

On the Compact Framework, the System.Windows.Forms.Timer class doesn't support the system.componentmodel constructor:
new Timer() is supported: http://msdn.microsoft.com/en-us/library/aa335543(v=vs.71).aspx
new Timer(IContainer container) is not supported: http://msdn.microsoft.com/en-us/library/aa335544(v=vs.71).aspx
This means that, when I add a Timer to a Form in a CF app, it does not get added to the form's IContainer components field, so it doesn't get auto-dispose()d when the form is dispose()d.
Why is this not supported?
How should I best dispose of Timers when my form is disposed? It seems that I have two main options:
move the form's dispose() method from the .designer.cs into my main .cs file and add a manual "_timer.dispose()" call in there
or manually add the Timer object to the components collection on form creation, after InitializeComponent() has been called
Which should I prefer? If I forget to do one of these two, the Timer will live forever, keeping my form alive (because the Timer can't be GCed, and it holds a reference to my form's Timer_Tick() method, so the form can never be GCed).
Does this implementation decision reflect some strangeness about Timers and Disposing on CF machines which I need to be aware of?

I'd vote for option 3: don't add the Timer through the Form Designer; instead add it manually in code and add it to the components collection manually as well.
My reasoning for this follows like this:
Mucking with the designer code is just generally a bad idea, so your first option has a code smell to it
Adding it to the components collection manually is highly prone to future developers (even yourself in a few months) no understanding why it's there and getting axed.
I generally don't like "mixing" object initialization. If the disigner is doing initialization of an object, it needs to do all of it or none of it, never just part. Having it do some partial work is deadly when the code is maintained or during reuse when someone does a copy & paste into some other class.

Related

How should you reload a form and have it re-initialize?

A older application loads some forms using implicit instances:
form2.showdialog()
Sometime between VS2008 32-bit and VS2013 64-bit, the forms stopped being initialized when they are reloaded. For example, if you load a form, close the form (using the Close method), and load the form again, the classes and controls (and, I assume, the form) are not initialized as new instances.
Re-initialization can be accomplished by putting me.dispose() in the FormClosed event, or by using an explicit instance of the form:
Using frm As New Form2
frm.ShowDialog()
End Using
Is there a good reason to use one of these methods over the other, or is there another method that should be used to cause a form to be initialized when it is reloaded?
Dispose will be called automatically if the form is shown using the Show method. If another method such as ShowDialog is used (your case it is), or the form is never shown at all, you must call Dispose yourself within your application. You can also handle the dispose by moving it from the designer file into the code file and handle things there as well.
On the other hand, Using statement typically makes your application safer to maintain and less prone to deadlocks and other misbehavior related to the lifecycle of the resource. I would stick by using this approach.
Also you cant put Me.Dispose in the Form Closed event (possible issues). If your using ShowDialog it will fail as it will dispose your objects first, if you need them they are gone.
Here's more on dispose: https://msdn.microsoft.com/en-us/library/aw58wzka(v=vs.110).aspx
The Form object and its child controls are not automatically disposed when you display the form with ShowDialog(). That sounds pretty quirky but this was done for a very good reason. After ShowDialog returns DialogResult.OK, you are normally going to obtain the dialog results. What nobody likes is that failing because of a ObjectDisposedException. Which would be likely to occur since the dialog results are often stored in controls.
You should always use the Using statement to ensure the form object and all of its controls are disposed.
A possible corner case is intentionally not disposing it because you like the redisplay the dialog with the original entered values. Which is not completely wrong, it is however a very expensive way to preserve those values. Those undisposed window objects cost an arm and a leg in system resources.
Pretty clear explanation from MSDN
Unlike non-modal forms, the Close method is not called by the .NET
Framework when the user clicks the close form button of a dialog box
or sets the value of the DialogResult property. Instead the form is
hidden and can be shown again without creating a new instance of the
dialog box. Because a form displayed as a dialog box is hidden instead
of closed, you must call the Dispose method of the form when the form
is no longer needed by your application.
When ShowDialog() called and closed, instance of the form will remain in the memory, and can be used again, for example get a result from some public property.
If you not using anymore this form, you need to call Dispose method to dispose form and form's controls
Dim myform As New MyDialogForm()
myform.ShowDialog()
Dim result As Object = myForm.SelectedResult()
myform.Dispose() 'need to call manually, if instance not used anymore
When you use Using keyword then Dispose method will be executed automatically at the end of the Using block
Dim result As Object
Using myform As New MyDialogForm()
myform.ShowDialog()
result = myForm.SelectedResult()
End Using 'myform.Dispose will be called
Bottom line: Both methods doing a same things.
But Using block will call Dispose method automatically
P.S. Putting Me.Dispose in the FormClosed eventhandler then
- instance of the form will stay in the memory even form was closed
- and will work only until you tried using disposed controls again. If you will try to show disposed object then ObjectDisposedException will be thrown.
If you not using form anymore then Using block will be best method

Issue with OpenFileDialog and threading

I just upgraded from VS 2005 to VS 2012. This is a new issue that I do not understand. I am using the default "Form1" class the VS automatically creates. I added a button to open a file open dialog and when I click the button I get this error:
Current thread must be set to single thread apartment (STA) mode before OLE calls can be >made. Ensure that your Main function has STAThreadAttribute marked on it. This exception >is only raised if a debugger is attached to the process.
I have added " to Public Class Form1:
<STAThread()> Public Class Form1
But I get this...
Attribute 'STAThreadAttribute' cannot be applied to 'Form1' because the attribute is not >valid on this declaration type.
I have searched but get some info telling me that I need to set the entry point (Form1 I believe) to be Single Thread Attribute but the above code does not work.
How?
The <STAThread()> attribute cannot be added to classes like your form. It only works when it is applied to the Main function, which is the entry point of your application.
But VB.NET hides this function from you because it is rare that one needs to mess with Main in a WinForms application. It is just needed to get the plumbing set up for your app, which the compiler can manage for you. This is controlled by the "Application Framework" checkbox in the project options. If this is checked, the compiler automatically generates the Main function and the required plumbing. You can disable this option, but it makes life quite a bit harder for the average WinForms developer because you'll have to write and maintain your own Main function.
The real question here is why this is a problem at all. The compiler-generated Main function for a WinForms application is always going to have the STAThread attribute applied to it. That is just how the WinForms framework is designed to run. If that is not happening, then there is something badly wrong with your project. I would recommend scrapping it and starting over letting Visual Studio create a new WinForms project from one of the built-in templates. Everything should Just Work™.
The other option, of course, is that you're trying to display the OpenFileDialog on a separate thread (other than your main UI thread). But from your description in the question (adding a button to the form to display the dialog), it doesn't sound like this is the case. Regardless, the solution is not to do that. For example, if you're using a BackgroundWorker to do work on a non-UI thread in order to keep the UI responsive, that's great, but you'll want to do all of the UI stuff like showing an OpenFileDialog on the main UI thread before invoking the BackgroundWorker. There is a way to set a particular thread's apartment state using the SetApartmentState function, but I really don't recommend showing an OpenFileDialog on a background thread.

What is the correct way to fully remove a control from a parent control/form?

I have a UI element in my application where a Panel is used to host one of several potential custom UserControls. The Panel itself is hosted in a standardised UserControl that I am using something like a non-modal dialog that I'm calling a 'pane'.
The method I use is to instantiate a new instance of the standard pane, then with logic instantiate one of the several optional hosted controls inside it using Panel.Controls.Add(control). I then add the new pane to the interface control in a set location, again with a Control.Controls.Add(control), followed by a control.BringToFront() to maximise its z position.
This all works well, however when the time comes to hide the pane and destroy it, I cannot seem to fully get rid of it. Originally I was simply using Control.Controls.Remove(control) and for good measure setting the pane's Parent property to Nothing. This would have the desired effect of making the pane disappear, and my assumption was that now the control was unreferenced, that GC would dispose of it.
What I am seeing however is that the control still blits instantaneously onto the screen when the next outer hosting TabControl changes tab page, implying it still exists somewhere. I can confirm that this is not a graphical issue and the pane object persists using the VS Watch window's 'Make Object ID'. (At least I think this is proof, that without a code-accessible reference I can still directly see the object and its properties continue to exist.)
I have tried replacing
Control.Controls.Remove(pane)
pane.Parent = Nothing
with
pane.Dispose()
GC.Collect()
where the Dispose call I can confirm both removes the control from its parent's Controls collection and sets its Parent property to Nothing, but appears to do no more. It persists after forced GC and still blits onscreen occasionally.
This all leads to my original question, what is the proper way to remove and fully destroy controls after they have served their purpose?
According to this article from MSDN it seems like you might be experiencing side affects from the object being on the finalization queue.
A Dispose method should call the GC.SuppressFinalize method for the object it is disposing. If the object is currently on the finalization queue, GC.SuppressFinalize prevents its Finalize method from being called.
Translation: The finalize method isn't being called, and so the resources associated with your control are not being released. After a bit more digging, I found that you should
Always call Dispose before you release your last reference to the Component. Otherwise, the resources it is using will not be freed until the garbage collector calls the Component object's Finalize method.
From this article.
So either you need to release your last reference OR you need to call the components finalize method directly so your GC.Collect() will work.

IntializeComponent keeps getting overwritten

I have some conditionals in my InitializeComponent which affect the layout based on some variables. Unfortunately, it seems like whenever I rebuild my application, this code is reverted back to its previous state. Is this code being regenerated based on the Designer interface? Is there a way to prevent it from doing this?
Yes, InitializeComponent is completely IDE-generated; don't even try to mess with it.
If you have conditional logic wherein you want to add/remove some controls, do it in your control's constructor after the auto-generated call to InitializeComponent.
Note that if the conditional stuff will depend on features enabled/disabled at design time (e.g., if someone else is using your control and you've provided properties to affect how that control behaves which you intend to be set at design time), using the constructor won't work since the constructor will have already run by the time the user makes his/her choices from the design view; in this case, override the OnLoad method and put your logic in there (or do some variation of this, e.g., handle the Load event itself—there are plenty of ways to skin this cat).

Lifetime of objects in a collection in VB.Net

I'm trying to figure out the lifetime of the tmpTabPages in the following bit of code. Lets assume the form has an empty TabControl named MyTabControl, that there's a collection of strings called NameCollection.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For Each itm In NameCollection
Dim tmpTabPage as New TabPage(itm.toString)
'Add Controls to tmpTabPage
MyTabControl.TabPages.Add(tmpTabPage)
Next
End Sub
Since the scope of the tmpTabPage is the For/Next block, typically it's lifetime would be until the end of the block right? But since it is added to a collection that has a scope outside of the block does it get the same lifetime as the collection, or in this case the MyTabControl? Finally, if I call MyTabControl.TabPages.Clear will the tmpTabPages in the collection be destroyed or will they just sit around taking up memory?
The big deal about classes derived from Control (including TabPage) is the Dispose() method. They are immune from automatic garbage collection, Winforms keeps an internal table that maps the Handle of a control to the control reference. That's why, say, your main form doesn't suddenly get garbage collected, even though your program doesn't keep a reference to it.
Adding the TabPage to the TabControl's collection takes care of automatic disposal. The same applies for the TabControl, it would be added to the form's Controls collection. The normal chain of events is that either your program or the user closes the form. The Form class iterates its child controls and calls their Dispose() method. TabControl does the same thing in its Dispose() method, disposing the tab pages. The Windows window gets destroyed in the process, removing the Handle from that mapping table and now allowing the garbage collector to, eventually, collect the managed wrapper for the controls.
There is a nasty trap that gets many Winforms programmers in trouble. If you remove a control from its parent's collection then you get the responsibility of disposing it yourself. Removing it does not automatically dispose it. Winforms keeps the native window alive by temporarily re-parenting the control to a hidden window named the "parking window". Nice feature, it allows you to move a control from one parent to another without having to destroy and re-create the control.
But the keyword there is "temporarily". It is only temporarily if you next reparent the control. So it gets moved from the parking window to the new parent. If you don't actually reparent it then it will stay alive for ever on the parking window. Gobbling up resources until the program terminates. This is otherwise known as a leak. It can crash your program when Windows refuses to create another window when you've already created 10,000 of them.
The ControlCollection.Clear() method is especially harmful here. It does not dispose the controls, they all get moved to that parking window. If that's not intended, it rarely is, you'll have to call Dispose() on them yourself.
Objects in .NET become eligible for garbage collection when there's no way of getting at them. In this case, there will be a way of getting at the TabPage via the TabPages collection, until either it's removed from the collection or the tab control itself becomes eligible for collection.
Now when an object becomes eligible for garbage collection, that doesn't mean it's garbage collected straight away - the garbage collection runs at various times according to some fairly complex heuristics, and there are also "generations" of memory which make things harder to predict.
But basically:
You don't need to worry that an object that's been added to a collection will be mysteriously collected and cause problems
You generally don't need to worry that objects will leak memory forever. There are certainly situations where you do need to take some active steps to make sure that an object is eligible for collection when you're no longer using it, but they're relatively rare. (Typically they are related to static variables and/or events, in my experience.)
because soemthing has a reference to the controls they will not be disposed of.
yes the lifetime would be till the end of the procedure if you were not adding a reference to them to the colelction.
the clear will remove the objects from the collection and they will get garbage collected provided there are no other references to them (which there shuoldnt be in the situation you describe)
You add only a reference of the TabPage object to the collection not the object TmpTabPage. The tmpTabPage object in this case you use it only for allocating memory.