更改控件的字体时是否应该处理旧字体?

Should I dispose of the old font when changing the font of a control?

C#,Windows 表单应用程序。

我们正在重新设计我们的应用程序,我也在更改我们在旧应用程序中使用的可怕的默认字体。所以我想我会调用以下函数来在加载窗体时更改窗体上所有控件的字体。

  internal static void SetFonts(Control control)
  {
    Font oldFont = control.Font;
    if (oldFont.Name != GlobalFontName)
    {
      string familyName = GlobalFontName;
      Font newFont = new System.Drawing.Font(familyName,
        oldFont.Size, oldFont.Style, GraphicsUnit.Point, 0);
      control.Font = newFont;
      //oldFont.Dispose();
    }
    foreach (Control child in control.Controls)
      SetFonts(child);
  }

我认为如果我在用新字体重新分配控件后处理掉旧字体会减少资源,但是在关闭表单时我收到来自一组第三方的一种控件类型的访问冲突异常控制。 如果我注释掉行 "oldFont.Dispose()" 那么我不会得到异常。

这是第三方控件集的错误还是在意料之中?
记忆方面,我可以不明确处理旧字体而逃脱吗(该应用程序每天在售货亭上运行 12 小时以上)?

不要处理旧字体,这是您要更改其字体的控件的工作。另外,使用 GDIView 等工具来监控您的句柄(例如字体)。

控件字体非常奇怪,因为 Font 对象实际上封装了两种不同的东西:

  1. 关于字体、排版样式等的信息
  2. 一个 GDI 字体句柄。

Font对象的后一方面封装了资源;前者没有。在 Font 对象上调用 Dispose 会释放后者,但不会破坏前者。

虽然我认为我没有在任何地方看到他们的行为 "officially",但内置控件似乎从未使用用于设置的 Font 对象实际绘制Font 属性;相反,他们使用分配的 Font 对象的属性来生成新的 GDI 字体对象,然后使用它来绘制控件。虽然在字体对象上调用 Dispose 会使它无法用作 DrawString 或其他此类方法的参数,但它不会阻止它用作 "template" 来创建新的字体对象。

这样做的结果是控件不关心分配的 Font 对象是否被释放(无论是在分配之前还是分配之后),它们也从不释放它。从控件读取 Font 属性 将始终 return 上次分配给它的相同 Font 对象,而不考虑 Font 对象是否被释放.因此,似乎如果没有任何东西会读取控件的 Font 属性 并期望用它来绘制,那么最安全的分配控件 Font 属性 的方法没有临时资源泄漏将是非常奇怪的样子:

using f = new Font(...)
  theControl.Font = f;

这可以说比读取控件的 Font 属性 并在分配新值之前处理它更安全,因为上面的 using 方法知道 Font 这是分配给该控件的不会用于任何其他用途,而后一种方法无法知道相同的 Font 是否被其他反对其处理的代码使用。

我真的希望 MS 记录了应该如何处理 Font 资源。不幸的是,据我所知他们还没有。

我决定将创建的字体存储到创建时的列表中,并在 form.Dispose() 期间处理它们。但是在某些 windows 上我也遇到了错误。

我刚刚意识到第三方控件也必须在 skinning/painting 期间更改它的字体,所以我在列表中的字体对控件不再有效并且可能已被 GC 处理.

因此存储字体供以后处理似乎并不安全,我想知道我是否应该存储已更改字体的控件。

到这个时候,继续沿着这条线前进的前景失去了吸引力,取而代之的是,我用 search/replace 而不是 lol

手动浏览了我应用程序中的所有 200 多个表单

不太满意