2014-07-15 98 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