So I've been having this issue when debugging, I get an Access Violation, but when I run without the Debugger, I get an Error that tells me that A Parameter is invalid. It lead me to path.AddString(...); Any reason as to why? Honestly, all Parameters are correct, else the compiler would catch it. This is making me angry.
protected override void OnPaint( PaintEventArgs e )
{
Graphics g = e.Graphics;
if ( !extended )
{
setColor ( );
g.FillRectangle ( new SolidBrush ( currColor ), this.ClientRectangle );
}
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
string szbuf = Program.AppName;
SolidBrush brushWhite = new SolidBrush ( Color.White );
g.FillRectangle ( brushWhite, 0, 0,
this.ClientSize.Width, this.ClientSize.Height );
FontFamily fontFamily = this.Font.FontFamily;
StringFormat strformat = StringFormat.GenericDefault;
SolidBrush brush = new SolidBrush ( Color.FromArgb ( 255, 255, 255 ) );
SizeF sz = g.MeasureString(szbuf, this.Font);
int w = ( ( this.Width / 2 ) - ( ( int ) sz.Width / 2 ) );
int h = 10;
GraphicsPath path = new GraphicsPath ( );
float emSize = g.DpiY * this.Font.Size / 72;
path.AddString ( szbuf, fontFamily, 0, 48f, new Point ( w, h ), strformat);
for ( int i = 1; i < 8; ++i )
{
Pen pen = new Pen ( getColor ( ), i ); //Color.FromArgb ( 32, 0, 128, 192 ), i );
pen.LineJoin = LineJoin.Round;
g.DrawPath ( pen, path );
pen.Dispose ( );
}
g.FillPath ( brush, path );
fontFamily.Dispose ( );
path.Dispose ( );
brush.Dispose ( );
g.Dispose ( );
}
With this line:
fontFamily.Dispose();
You're disposing this.Font.FontFamily
object. Control
will be in an invalid state and next call to Paint
will fail. You're also disposing Graphics
object, do not do it because it may be used after your function.
In general you have to dispose only objects you created, nothing more and nothing less (creator owns responsibility to dispose that objects). Compiler can't catch this kind of errors (unless you run a static code analysis) because it's a run-time error caused by program execution path. If you're lucky you'll have an exception (ArgumentException
because you're passing an invalid argument: a disposed font).
Moreover you don't need to call Dispose()
explicitly, it's more safe to use using
statement (it'll work also in case of exceptions). Let me refactor little bit your code:
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
if (!extended)
{
setColor();
using (var backgroundBrush = new SolidBrush(currColor))
{
g.FillRectangle(backgroundBrush, this.ClientRectangle);
}
}
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
string szbuf = Program.AppName;
g.FillRectangle(Brushes.White, 0, 0,
this.ClientSize.Width, this.ClientSize.Height);
StringFormat strformat = StringFormat.GenericDefault;
SizeF sz = g.MeasureString(szbuf, this.Font);
int w = ((this.Width / 2) - ((int)sz.Width / 2));
int h = 10;
using (var path = new GraphicsPath())
{
float emSize = g.DpiY * this.Font.Size / 72;
path.AddString(szbuf, Font.FontFamily, 0, 48f, new Point(w, h), strformat);
for (int i = 1; i < 8; ++i)
{
using (var pen = new Pen(getColor(), i))
{
pen.LineJoin = LineJoin.Round;
g.DrawPath(pen, path);
}
}
g.FillPath(Brushes.White, path);
}
}
Please note that to create resources for each paint isn't efficient (allowed but very slow). You should reuse them as much as possible (for example using a dictionary). Moreover for constant colors it's better to use predefined brushes (for example Brushes.White
, do not dispose them). Let me show a very naive implementation (easy to extend to cache both Pen
and SolidBrush
):
private Dictionary<Color, SolidBrush> _solidBrushes;
private SolidBrush GetSolidBrush(Color color)
{
if (_solidBrushes == null)
_solidBrushes = new Dictionary<Color, SolidBrush>();
if (!_solidBrushes.ContainsKey(color))
_solidBrushes.Add(color, new SolidBrush(color));
return _solidBrushes[color];
}
Then it'll be used like this:
if (!extended)
{
setColor();
g.FillRectangle(GetSolidBrush(currColor), this.ClientRectangle);
}