以前WPF里有个{x:Static Fonts.SystemFontFamilies}可以很方便的绑定系统字体列表,结果UWP里被微软撸掉了,Stupid!
这两天写了个UWP版的字符映射表APP,正好要用到字体功能,于是研究了一下。
在UWP里获取系统字体必须得用DirectX渲染,没错,就是做游戏用的那个DX。
从NuGet引这3个包:
"SharpDX": "3.0.1", "SharpDX.Direct2D1": "3.0.1", "SharpDX.DXGI": "3.0.1"
然后写个InstalledFont类:
这个类的代码是我改进过的,SharpDX官方的代码是会爆的,在一些中文系统的计算机上会产生错误的index,然后爆一个HResult什么的看也看不懂但是觉得很牛逼然而还是没有什么卵用的错。
其中,Name是字体名称,FamilyIndex是字体在它所属Family中的序号,Index是字体在系统所有字体列表中的序号。
GetFonts()方法就能返回所有的系统字体。
public class InstalledFont { public string Name { get; set; } public int FamilyIndex { get; set; } public int Index { get; set; } public static List<InstalledFont> GetFonts() { var fontList = new List<InstalledFont>(); var factory = new Factory(); var fontCollection = factory.GetSystemFontCollection(false); var familyCount = fontCollection.FontFamilyCount; for (int i = 0; i < familyCount; i++) { var fontFamily = fontCollection.GetFontFamily(i); var familyNames = fontFamily.FamilyNames; int index; if (!familyNames.FindLocaleName(CultureInfo.CurrentCulture.Name, out index)) { if (!familyNames.FindLocaleName("en-us", out index)) { index = 0; } } string name = familyNames.GetString(index); fontList.Add(new InstalledFont() { Name = name, FamilyIndex = i, Index = index }); } return fontList; } public List<Character> GetCharacters() { var factory = new Factory(); var fontCollection = factory.GetSystemFontCollection(false); var fontFamily = fontCollection.GetFontFamily(FamilyIndex); var font = fontFamily.GetFont(Index); var characters = new List<Character>(); var count = 65535; for (var i = 0; i < count; i++) { if (font.HasCharacter(i)) { characters.Add(new Character() { Char = char.ConvertFromUtf32(i), UnicodeIndex = i }); } } return characters; } }
里面的Character类型代表一个字符。
public class Character { public string Char { get; set; } public int UnicodeIndex { get; set; } }
前台绑定(非MVVM的写法,当然你也可以自行用MVVM装逼)
var fontList = InstalledFont.GetFonts(); CmbFontFamily.ItemsSource = fontList;
<ComboBox Grid.Row="0" x:Name="CmbFontFamily" x:Uid="CmbFontFamily" Width="300" SelectionChanged="CmbFontFamily_OnSelectionChanged" SelectedValuePath="Name"> <ComboBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name}" /> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox>
如果要显示Unicode编码,就用Character里的那个UnicodeIndex。在WIN32的字符映射表里显示的是看上去很牛逼的U+EXXXX这样的,我们也可以装一下逼。
C#里面int转16进制的string只要ToString("X")就好了,然后再ToUpper()全部大写,把逼装完:
TxtUnicode.Text = "U+" + ch.UnicodeIndex.ToString("x").ToUpper();