Reputation: 5586
I've been trying to identify a memory leak with a custom control when I've noticed something odd:
Private f = Me.Font
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
If f IsNot Me.Font Then 'ALWAYS TRUE
f.Dispose()
f = Me.Font
End If
...
End Sub
Me.Font returns a different instance each time which has lead me to question other cases where I have called Me.Font.
Normally this isn't a big deal but paint can be called up to every 500ms in this control.
Is Me.Font generated each time it is called an therefore should be disposed each time? Are there any other control properties like this i need to be wary of?
Upvotes: 2
Views: 298
Reputation: 18320
If you are using a control inherited from System.Windows.Forms.Control
and you haven't changed the current font nor the default font of it, this seems pretty logical.
If we take a look at Microsoft's Reference Source for the .NET Framework we can see that the Control.Font
property initially tries to get the current font of the control:
Font font = (Font)Properties.GetObject(PropFont);
if (font != null) {
return font;
}
If there is no current font (if its null
, or Nothing
in Visual Basic) it tries to get its parent's font instead:
Font f = GetParentFont();
if (f != null) {
return f;
}
Now, GetParentFont()
will return null
if the control has no parent (this could go all the way back until it gets to the parent form). If this gets to the last parent GetParentFont()
will return null
, thus making the execution continue. Since the control is not an ActiveX control the if (IsActiveX)
check will fail and move on to:
AmbientProperties ambient = AmbientPropertiesService;
if (ambient != null && ambient.Font != null) {
return ambient.Font;
}
I am not sure what this does but if even that check fails we're getting to the interesting part:
return DefaultFont;
The control returns the DefaultFont
property, and if we go to its code:
if (defaultFont == null) {
defaultFont = SystemFonts.DefaultFont;
Debug.Assert(defaultFont != null, "defaultFont wasn't set!");
}
return defaultFont;
we can see that it checks if the control already has defined its own default font, and if it hasn't it will return the default font for all standard controls (via SystemFonts.DefaultFont
).
If we finally jump to the code for SystemFonts.DefaultFont
we can see that it will create a variable called defaultFont
, which it will return in the end.
Font defaultFont = null;
Now when looking on how the variable is assigned, we can see that it always creates a new Font
instance (which would be what causes your issue):
//Each line represents an example taken from the code.
defaultFont = new Font("MS UI Gothic", 9);
defaultFont = new Font("Tahoma", 8); //This appears two times.
defaultFont = new Font(FontFamily.GenericSansSerif, 8);
defaultFont = FontInPoints(defaultFont);
//FontInPoints only have one line: "return new Font(...);"
So we can now draw the conclusion that every time you call YourControl.Font
it will return a new Font
instance if you haven't assigned a custom font/custom default font, and if all other checks fail making it get the Windows' default font.
Upvotes: 2