嵌入字体仅在Label生效,如何让DataGridView单元格应用自定义字体?
解决DataGridView嵌入自定义字体不生效的问题
问题根源
使用AddMemoryFont加载嵌入字体时,PrivateFontCollection中的字体并未被系统注册,而DataGridView的单元格渲染机制与Label不同——Label可以直接使用内存字体,但DataGridView更依赖系统已识别的字体,或需要确保字体对象与对应的PrivateFontCollection生命周期完全绑定。
解决方案
方案1:临时安装嵌入字体到系统(兼容性最优)
将嵌入字体写入临时文件并注册到系统,让DataGridView像使用系统字体一样加载它,应用退出时自动清理。
修改Program.cs代码:
internal static class Program { [STAThread] static void Main() { ApplicationConfiguration.Initialize(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(true); Application.Run(new Main()); } static public Font InstallTempFont(byte[] fontData, float size, FontStyle style) { // 生成临时字体文件路径 string tempFontPath = Path.Combine(Path.GetTempPath(), "Circulitos.ttf"); File.WriteAllBytes(tempFontPath, fontData); // 注册字体到系统并通知系统更新 AddFontResource(tempFontPath); SendMessage(HWND_BROADCAST, WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero); // 应用退出时清理临时文件与注册的字体 Application.ApplicationExit += delegate { RemoveFontResource(tempFontPath); SendMessage(HWND_BROADCAST, WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero); if (File.Exists(tempFontPath)) File.Delete(tempFontPath); }; return new Font("Circulitos", size, style); } // 导入Win32 API用于字体注册与通知 [DllImport("gdi32.dll")] private static extern int AddFontResource(string lpFileName); [DllImport("gdi32.dll")] private static extern bool RemoveFontResource(string lpFileName); [DllImport("user32.dll")] private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); private const int WM_FONTCHANGE = 0x001D; private static readonly IntPtr HWND_BROADCAST = new IntPtr(0xffff); }
修改Main.cs调用逻辑:
public partial class Main : Form { private Font gf; public Main() { InitializeComponent(); // 使用临时安装的字体 gf = Program.InstallTempFont(Properties.Resources.Circulitos, 10, FontStyle.Regular); // 初始化DataGridView字体样式 SetupDataGridViewFont(); } private void SetupDataGridViewFont() { dataGridView1.EnableHeadersVisualStyles = false; // 设置所有单元格默认字体 dataGridView1.DefaultCellStyle.Font = gf; // 设置表头字体 dataGridView1.ColumnHeadersDefaultCellStyle.Font = gf; dataGridView1.RowHeadersDefaultCellStyle.Font = gf; // 手动刷新样式 dataGridView1.Refresh(); } }
方案2:确保PrivateFontCollection生命周期与应用绑定
复用同一个PrivateFontCollection存储内存字体,避免因多个实例导致的字体对象失效,并通过CellFormatting事件强制设置单元格字体。
修改Program.cs代码:
internal static class Program { static private PrivateFontCollection _fontCollection; [STAThread] static void Main() { ApplicationConfiguration.Initialize(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(true); Application.ApplicationExit += delegate { _fontCollection?.Dispose(); }; Application.Run(new Main()); } static public Font GetCustomFont(byte[] fontData, float size, FontStyle style) { if (_fontCollection == null) { _fontCollection = new PrivateFontCollection(); IntPtr fontPtr = Marshal.AllocCoTaskMem(fontData.Length); Marshal.Copy(fontData, 0, fontPtr, fontData.Length); _fontCollection.AddMemoryFont(fontPtr, fontData.Length); Marshal.FreeCoTaskMem(fontPtr); } return new Font(_fontCollection.Families[0], size, style); } }
修改Main.cs添加事件处理:
public partial class Main : Form { private Font gf; public Main() { InitializeComponent(); gf = Program.GetCustomFont(Properties.Resources.Circulitos, 10, FontStyle.Regular); SetupDataGridViewFont(); // 绑定CellFormatting事件确保字体生效 dataGridView1.CellFormatting += DataGridView1_CellFormatting; } private void SetupDataGridViewFont() { dataGridView1.EnableHeadersVisualStyles = false; dataGridView1.DefaultCellStyle.Font = gf; dataGridView1.ColumnHeadersDefaultCellStyle.Font = gf; dataGridView1.RowHeadersDefaultCellStyle.Font = gf; } private void DataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { // 强制为每个单元格设置字体,避免样式被覆盖 if (e.RowIndex >= 0 && e.ColumnIndex >= 0) { dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.Font = gf; } } }
内容的提问来源于stack exchange,提问作者jhu unhn hefhd
相关产品推荐
相关产品推荐

