2014-07-15 60 views
1

所以我一直有这个问题,当调试,我得到一个访问冲突,但是当我没有调试器运行,我得到一个错误,告诉我,一个参数是无效的。它将我引向path.AddString(...);任何理由为什么?老实说,所有的参数都是正确的,否则编译器会抓住它。这让我很生气。System.ArgumentException:参数无效。 GraphicsPath.AddString

 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 (); 
     } 
+0

“否则,编译器会抓住它” - 这通常不是事实。编译器可以告诉你是否将错误的类型传递给了某些东西,但是如果类型正确,但是该值错误,编译器将无法辨别。例如,如果你正在创建一个图像并指定x和y尺寸,编译器会看到一个int进入并且很快乐,但是如果这个int是'-1',那么我会希望该方法在运行时断开,并告诉我一个异常我传递了一个无效值。 – Chris

+0

我应该注意到,我并不是说你传递的是负宽度或类似的东西,只是解释你对编译器能够停止发生的误解。也许这会帮助你弄清楚自己正在发生什么。 – Chris

+0

另外一个stacktrace通常有助于指出事情出错的确切位置。我认为这就是导致你进行'path.AddString'调用的原因,但是我们有时看到完整的堆栈跟踪和实际的异常类型有助于调试。 – Chris

回答

2

这一行:

fontFamily.Dispose(); 

你处置this.Font.FontFamily对象。 Control将处于无效状态,下一次拨打Paint将失败。你也在处理Graphics对象,不要这样做,因为它可能在你的函数之后被使用。

一般来说,你必须只处理你创建的对象,没有别的也没有少(创建者拥有处置该对象的责任)。编译器无法捕获这种错误(除非运行静态代码分析),因为这是由程序执行路径引起的运行时错误。如果你幸运的话,你会有一个例外(ArgumentException,因为你传递了一个无效的参数:一种处理过的字体)。

此外,您不需要明确地调用Dispose(),使用using语句更安全(它也适用于异常情况)。让我重构点点代码

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); 
    } 
} 

请注意,创建资源对于每个油漆是效率不高(允许的,但很慢)。你应该尽可能地重用它们(例如使用字典)。此外,对于不变的颜色,最好使用预定义的画笔(例如Brushes.White,不要将它们处理)。让我告诉一个很天真的实现(易于扩展到同时缓存PenSolidBrush):

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]; 
} 

然后,它会像这样使用:

if (!extended) 
{ 
    setColor(); 
    g.FillRectangle(GetSolidBrush(currColor), this.ClientRectangle); 
} 
+0

谢谢!我需要停止写作,就像我7年前写作的那样,这是一个坏习惯。 – Blizzardo1