When I finalized my article about memory leaks, I removed a part about Infragistics NetAdvantage. Here it is. It may be useful to some of you. Warning: It's based on NetAdvantage 7.3, and may or may not apply to recent versions.
Let's take an example. In project X, visual controls from the Infragistics NetAdvantage suite are used to build the GUI. One of these controls is the UltraToolbar. As told by its name, this control is used to display toolbars. The way a UltraToolbar is used is via a UltraToolbarsManager component. This works fine, except that even though the UltraToolbar class implements IDisposable, the UltraToolbarsManager class never calls the Dispose method on the UltraToolbars it manages. This is a bug. Fortunately, a workaround is easy to find: just call Dispose by yourself on each UltraToolbar. Unfortunately, this is not enough because UltraToolbar itself is buggy: it does not dispose the controls (buttons, labels, etc.) it contains. Again, the solution is to dispose each control the toolbar contain, but that's not so easy this time because each sub-control is different. Infragistics has the same problem with another set of objects: the custom editors you can create for cells in grids are not disposed automatically either.
Anyway, these are just specific examples. My point is that any libraries and components you use may cause leaks in your applications.
Later in the article:
Let's take an interesting example that shows another particularity of Infragistics NetAdvantage. The scenario is simple: just dynamically add a button to a form. The only special thing about this button is that it will be an UltraButton from Infragistics NetAdvantage.
Here is how the button is added to the form (UltraButtonForm.cs):
_ultraButton = new UltraButton();
_ultraButton.Text = "UltraButton";
_ultraButton.Location = new Point(10, 100);
Nothing fancy here. We just create a new instance of UltraButton and add it to the list of controls of the form so that it gets displayed. This works fine. Even when the form is closed/disposed, everything gets released.
Now, let's do one more little thing: remove the button before closing the form.
Guess what: now there is a problem! And potentially a big one.
The problem is that the UltraButton is not released from memory this time. And it's not alone, as I'll show soon.
As you can see, the button is kept alive by an event from the Infragistics.Win.Office2007ColorTable class named ColorSchemeChanged. This happens because this is a static event and UltraButton uses its Dispose method to unsubscribe from this event.
Without the call to Controls.Remove, everything was fine because all the controls contained in the Controls property of a Windows Forms Control are automatically disposed. When a control is removed from the Controls collection, it won't be disposed unless you do it explicitely yourself.
Here, the leak is due to a static event named ColorSchemeChanged, or one of its friends. The only way to ensure that such references get released is to make sure that Dispose is invoked on ALL the Infragistics controls. This is achieved via invoking Dispose on all the other controls.
If you use Infragistics NetAdvantage you may already have seen ColorSchemeChanged, Office2007ColorTable, and their friend, and maybe thought that there was a bug in them that caused leaks. As you have seen, this is not a bug per se, but it can be a source of memory leaks if you don't pay careful attention to ensure that all controls get disposed.
So, we've just seen again what I exposed above with static events. What I want to stress here is that it's easy to introduce a leak with just a line of code. Would you have thought about memory leaks when adding the call to Controls.Remove?
An UltraButton may not be a big object, but if you have several of them and if you do the same operation multiple times, you'll start to see a bigger leak. In addition, this doesn't happen only with UltraButton, but also with most of the other Infragistics controls, and potentially with other objects that subscribe to static events and depend on Dispose for unsubscribing. The only way to ensure that all objects get fully released is to make sure that Dispose is invoked on all controls.