SharpDX 4.2.0使用自定义TrueType字体绘图报错,求解决方案
解决SharpDX 4.2.0自定义字体绘制时的ObjectDisposedException问题
核心原因
SharpDX 4.x对COM对象的引用计数管理做了更严格的调整,3.0.0版本的示例代码没有适配这种变化,导致字体相关的COM对象被提前释放,调用DrawText时触发异常。
具体修复步骤
1. 绑定字体加载器与DWrite工厂的生命周期
SharpDX 4.x中,自定义字体加载器(CustomFontCollectionLoader/CustomFontFileLoader)必须存活到DWrite工厂被释放为止:
- 将加载器实例声明为类级成员变量,而非局部变量,避免被GC提前回收。
- 不要在加载完字体后手动调用加载器的
Dispose()方法,SharpDX会在DWrite工厂释放时自动处理这些依赖对象。
2. 修正字体集合的创建逻辑
创建FontCollection时,确保加载器被正确注册到DWrite工厂:
// 类级成员变量 private CustomFontCollectionLoader _fontCollectionLoader; private FontCollection _customFontCollection; // 初始化逻辑 var factory = new SharpDX.DirectWrite.Factory(); var fontBytes = File.ReadAllBytes("your-custom-font.ttf"); var fontFileStream = new CustomFontFileStream(fontBytes); var fontFileLoader = new CustomFontFileLoader(fontFileStream); _fontCollectionLoader = new CustomFontCollectionLoader(fontFileLoader); factory.RegisterFontCollectionLoader(_fontCollectionLoader); var collectionKey = new FontCollectionKey(Guid.NewGuid().ToByteArray()); _customFontCollection = new FontCollection(factory, _fontCollectionLoader, collectionKey);
3. 管控TextFormat/TextLayout的生命周期
- 确保
TextFormat和TextLayout的创建晚于字体集合,且它们的生命周期不超过DWrite工厂和字体集合。 - 不要在这些对象被使用前释放任何依赖项。
4. 禁止手动Dispose依赖对象
SharpDX 4.x的COM对象采用自动引用计数,手动调用Dispose()会提前释放对象,导致后续绘制时引用失效。除非确定对象不再被使用,否则不要手动调用该方法。
5. 验证字体加载状态
创建TextFormat后,可通过以下代码确认字体是否正确加载:
var textFormat = new TextFormat(factory, "Your Custom Font Name", _customFontCollection, FontWeight.Normal, FontStyle.Normal, FontStretch.Normal, 16); // 检查字体家族是否有效 if (textFormat.FontFamily.FamilyNames.Count == 0) { throw new InvalidOperationException("自定义字体未正确加载"); }
额外注意事项
- 确保D2D RenderTarget和DWrite工厂的线程模型一致(默认均为单线程公寓STA),跨线程访问COM对象也会触发异常。
- 若使用内存流加载字体,需确保流对象在字体使用期间保持存活,不要提前关闭或释放。
内容的提问来源于stack exchange,提问作者Undead
相关产品推荐
相关产品推荐

