PowerShell WinForms按钮WingDings3字体0x84字符无法显示问题
问题描述
尝试在PowerShell编写的WinForms窗体按钮上,使用WingDings 3字体的[char]0x84作为前进箭头字符,和已经正常显示的[char]0x83后退箭头配对,但前进箭头始终无法在按钮上显示。
测试发现其他十六进制值对应的WingDings 3字符均可正常渲染,所有字符编码均从MS Word中获取。最小可复现代码如下,运行后后退按钮显示正常、前进按钮显示空白,附带一个测试用备用按钮:
Add-Type -AssemblyName System.Windows.Forms $Form = New-Object system.Windows.Forms.Form $Form.Size = '800,600' $buttFACE1 = [char]0x83 # WingDings3后退箭头 $buttFACE2 = [char]0x84 # WingDings3前进箭头 <- 无法显示 $buttFACE3 = [char]0x86 # 测试用备用按钮字符 $navFONT = New-Object System.Drawing.Font("WingDings 3","14",[System.Drawing.FontStyle]::Bold) ################################################# # 后退按钮 $navBACK = New-Object System.Windows.Forms.Button $navBACK.Location = '10,10' $navBACK.Size = '30,30' $navBack.Font = $navFONT $navBACK.Text = $buttFACE1 $navBACK.Enabled = $True $Form.Controls.Add($navBACK) #################################################### # 前进按钮 $navFORWARD = New-Object System.Windows.Forms.Button $navFORWARD.Location = '50,10' $navFORWARD.Size = '30,30' $navFORWARD.Font = $navFONT $navFORWARD.Text = $buttFACE2 $navFORWARD.Enabled = $True $Form.Controls.Add($navFORWARD) ################################################## # 测试备用按钮 $navSPARE = New-Object System.Windows.Forms.Button $navSPARE.Location = '90,10' $navSPARE.Size = '30,30' $navSPARE.Font = $navFONT $navSPARE.Text = $buttFACE3 $navSPARE.Enabled = $True $Form.Controls.Add($navSPARE) $Form.ShowDialog()
可以直接换用其他符号实现需求,但需要明确单个字符无法正常工作的根本原因。
根本原因
0x84属于Unicode C1控制字符段(范围0x80~0x9F),WinForms默认的GDI+文本渲染管线会自动拦截处理这个区间的控制字符,不会将字符传递给WingDings 3字体查找对应字形,最终显示为空白。
你在MS Word中看到的0x84是WingDings 3字体本地的单字节编码值,不是该字符对应的标准Unicode码位:Wingdings这类传统符号字体的单字节编码,实际映射到Unicode私人使用区(PUA)的0xF000~0xF0FF段,直接取低字节值转char会命中控制字符区间,出现渲染异常。部分同区间字符(比如你用的0x83)能显示只是渲染路径的偶然兼容,不是正确用法。
修复方案
直接将前进箭头的字符值替换为PUA区对应码位即可,不需要修改其他配置:
$buttFACE2 = [char]0xF084 # 对应WingDings3前进箭头的正确Unicode码位
如果需要兼容旧代码逻辑,也可以把对应按钮的UseCompatibleTextRendering属性设为$true,切换到旧版GDI渲染路径,该路径会直接传递字符给字体查找字形,不会拦截控制字符段,但优先推荐使用正确码位的方案。
内容的提问来源于stack exchange,提问作者Doofus

