System.Drawing.Font使用PrivateFontCollection设置RichTextBox字体不生效
问题根因
- 私有字体不生效:
PrivateFontCollection如果声明为方法内局部变量,赋值完成后会被GC回收,非系统注册的私有字体对应的非托管资源被释放后,RichTextBox找不到有效字体资源会自动回退到默认Calibri字体。 - 字体仅部分生效、末尾显示Calibri:
SelectAll()方法不会选中RichTextBox内容末尾的隐式段落标记,未被选中的段落会沿用控件默认字体;如果是加载已有RTF文件的场景,RTF内嵌的字体表规则会覆盖控件属性设置的字体。 - 生成的RTF文件仍显示Calibri:默认情况下RTF不会嵌入私有字体资源,未安装对应字体的设备打开文件时会自动替换为系统默认字体。
修复实现
- 将字体相关对象声明为类级别的全局变量,保持引用避免被GC回收:
// 放在窗体/自定义控件类的全局作用域,不要写在业务方法内部 private readonly System.Drawing.Text.PrivateFontCollection _privateFontCollection = new(); private Font _targetCustomFont;
- 初始化阶段加载私有字体,提前创建字体实例:
// 初始化逻辑(比如窗体构造函数、Load事件中执行) _privateFontCollection.AddFontFile(@"C:\path\to\your\custom.ttf"); _targetCustomFont = new Font(_privateFontCollection.Families[0], 12f, FontStyle.Regular);
- 正确设置RichTextBox字体,覆盖全场景:
var RTB = new System.Windows.Forms.RichTextBox(); // 先设置控件全局默认字体,后续新输入内容会默认使用该字体 RTB.Font = _targetCustomFont; // 针对已有内容/加载RTF后的场景,显式选中全部内容范围,不要用SelectAll() RTB.Select(0, RTB.TextLength); RTB.SelectionFont = _targetCustomFont; // 取消全选,将光标定位到内容末尾 RTB.Select(RTB.TextLength, 0);
注意事项:只要RichTextBox还在使用该自定义字体,就不要主动释放
_privateFontCollection和_targetCustomFont对象,否则资源回收后字体会再次失效。如果需要生成的RTF文件在未安装该字体的设备上正常显示,需要手动编写逻辑将字体数据嵌入RTF字体表。
内容的提问来源于stack exchange,提问作者Leonardo Ferrari
相关产品推荐
相关产品推荐

