在Winform时代图标,图标都是在资源文件下创建JPG或者PNG来作为图片实现,但是随着TTF字体图标的普及,图标类型的图片越来越多的被放入到TTF中。 比如fontawesome 、iconfont 等,本文以iconfont为例聊一聊在WPF下如何使用TTF字体作为图标。
下载
iconfont是阿里巴巴下面的矢量图标管理、交流平台,用户注册登录后,可以在上面搜索和下载需要的矢量图标。
第一步是搜索需要的图标,然后将其添加到购物车:
等所有想要的图标都添加到购物车之后,可以点击“下载代码”,这里以我前面的NTP时间同步程序需要的11个图标为例:
下载完成之后,它是一个压缩包,解压出来:
在WPF中,真正需要用到的是.ttf这个文件,.html这个文件可以帮助提供所需图标的对应代码。
使用
要使用ttf文件,首先要将上述安装包里面的.ttf文件加入到项目中来,并将其编译属性设置为“资源”。
现在可以在代码中使用了。我这里有两个场景,一个是作为按钮的图片,一个是作为弹出菜单的ico,这里分别讲解。
作为按钮的图片很简单。
在按钮前面添加图片,只需要将按钮的Content设置为StackPanel,然后在里面水平放置两个TextBlock,将第一个TextBlock的Text属性设置为字体图标即可,注意,这里是TextBlock不是Image:
<Button Margin="15 5 0 5" VerticalAlignment="Center" Name="btnSettingTiming" Click="BtnSettingTiming_OnClick">
<StackPanel Orientation="Horizontal">
<TextBlock Text="" FontFamily="/Resources/#iconfont" FontSize="14" VerticalAlignment="Center"></TextBlock>
<TextBlock Name="btnSettingTimingText" Text="{DynamicResource S.TimeSetting.SettingTime}" Margin="5 0 0 0"/>
</StackPanel>
</Button>
第一个TextBlock就是图标,这里设置了FontFamily为Resources文件夹下的iconfont.ttf文件,需要注意的是,FontFamily的规则是: # + 字体名称(去掉.ttf),字体的文件名是iconfont.ttf,所以在这里面设置的就是#iconfont。
第二个就是Text属性,这个属性指定了tff文件里面的哪个图标,可以在提供的.html文件里查看。
这里闹钟图标是“”,所以Text属性设置为“”,注意当在C#代码中指定是,需要换为“0xe61f;”。
这里是将TextBlock的文字作为了图片。有时候比如MenuItem也需要图片,当然,也可以在MenuItem的Header中做如上的操作:
<MenuItem Header="{DynamicResource S.Options.Language.English}" Tag="en" IsCheckable="True" Click="MenuItem_Click">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="" FontFamily="/Resources/#iconfont" FontSize="14" VerticalAlignment="Center"/>
<TextBlock Text="{DynamicResource S.Options.Language.English}" Margin="5 0 0 0"/>
</StackPanel>
</MenuItem.Header>
</MenuItem>
但这实际上这是在菜单的文字前面放了一张图片,MenuItem有专门显示图标的位置,就是.ICO属性,它是一个image对象,那么如何将一个字体图标转换为image对象呢?有一些繁琐,如下:
MenuItem Header="{DynamicResource S.TimeSetting.SyncNow}" Command="{StaticResource SyncNow}" CommandTarget="{Binding Path=PlacementTarget,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ContextMenu}}}" >
<MenuItem.Icon>
<Image Stretch="None">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing>
<GeometryDrawing.Brush>
<VisualBrush Stretch="Uniform">
<VisualBrush.Visual>
<TextBlock FontFamily="/Resources/#iconfont" Text=""/>
</VisualBrush.Visual>
</VisualBrush>
</GeometryDrawing.Brush>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,32,32"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</MenuItem.Icon>
</MenuItem>
当然,可以将这些XAML代码转换为类,先定义一个继承自StaticResourceExtension的名为IconImageExtension的类:
[MarkupExtensionReturnType(typeof(DrawingImage))]
public class IconImageExtension : StaticResourceExtension
{
private static readonly FontFamily fontFamily
//= new FontFamily("file:///D:/Study/WPFStudy/WPFStudy/NTPClock/Resources/#iconfont");
= new FontFamily(new Uri("pack://application:,,,/"), "./Resources/#iconfont");
public int SymbolCode { get; set; }
public double SymbolSize { get; set; } = 16;
public override object ProvideValue(IServiceProvider serviceProvider)
{
var textBlock = new TextBlock
{
FontFamily = fontFamily,
Text = char.ConvertFromUtf32(SymbolCode)
};
var brush = new VisualBrush
{
Visual = textBlock,
Stretch = Stretch.Uniform
};
var drawing = new GeometryDrawing
{
Brush = brush,
Geometry = new RectangleGeometry(
new Rect(0, 0, SymbolSize, SymbolSize))
};
return new DrawingImage(drawing);
}
}
这里要特别注意的是FontFamily的加载方式。有了这个扩展类,前面的一大段XAML语句就可以简化为:
<MenuItem Header="{DynamicResource S.TimeSetting.SyncNow}" Command="{StaticResource SyncNow}" CommandTarget="{Binding Path=PlacementTarget,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ContextMenu}}}" >
<MenuItem.Icon>
<Image Stretch="None" Source="{local:IconImage SymbolSize=16, SymbolCode=0xe613}"/>
</MenuItem.Icon>
</MenuItem>
参考
- https://www.cnblogs.com/msjqd/p/14790480.html
- https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.fontfamily?redirectedfrom=MSDN&view=windowsdesktop-6.0
- https://stackoverflow.com/questions/6453640/how-to-include-external-font-in-wpf-application-without-installing-it
- https://stackoverflow.com/questions/62936619/how-to-set-a-segoe-mdl-font-icon-as-image-source-in-wpf
- https://www.cnblogs.com/mq0036/p/12379862.html