WPF 中的字符映射表






4.73/5 (8投票s)
字符映射是 Windows 机器中一个免费的实用程序。它类似于一些 MS Office 应用程序中的“插入符号”工具。本文介绍了如何使用 WPF 实现此工具。
引言
字符映射实用程序在所有 Windows 机器上都是免费的,可用于将重音字母和其他外语字符复制并粘贴到任何 Windows 应用程序中。字符映射类似于在某些 Windows 应用程序(如Microsoft Word)中找到的插入符号工具。
本文介绍了如何使用 WPF 以出色的性能实现此工具。此工具可以轻松集成到您的任何 WPF 应用程序中。
使用代码
当我想开始在 WPF 中实现它时,我意识到最大的挑战将是性能。但是 Windows 中的原生字符映射真的更快,并且会提供良好的用户体验。因此,我确信只有当这个工具也能提供相同的体验时,这篇文章才有效。
获取符号
让我首先从字体文件中获取符号开始。在 WPF 中使用已安装的字体系列填充一个ComboBox
并不是什么大问题。该文章解释了如何做到这一点。而且代码也很简单。
<ComboBox ItemsSource="{x:Static Fonts.SystemFontFamilies}" />
要从 Typeface 获取可用符号,首先迭代字体系列中的字样并选择合适的字样。一旦你获得了 Typeface,就可以获得给你字符映射字典的字形。
IDictionary<int, ushort> characterMap;
foreach (Typeface typeface in font.GetTypefaces())
{
typeface.TryGetGlyphTypeface(out glyph);
if (glyph != null)
{
characterMap = glyph.CharacterToGlyphMap;
}
}
变量characterMap
是一个字典,它存储我们符号的 unicode 值。所以现在我们可以继续在 UI 中显示符号。
符号 UI
正如我之前所说,性能将成为 WPF 中的主要瓶颈。因为某些字体系列可能包含超过 20,000 个符号。如果你想用传统的 ListBox 在一个 WrapPanel 中显示它们,你将失去 Windows 默认字符映射所拥有的用户体验。我确信在这个代码项目中有针对 WPF 的 Virtualization Wrap Panel 文章。但我将使用更好的东西,我们不需要关心容器的生成和处置。
我将使用 Canvas,我决定我的视口大小为 345 X 250,且不超过该值。基于此,我将 150 个SymbolView
(保存符号的视图)对象以水平换行的方式放置到画布中。每个视图将有一个文本框,显示相应符号 unicode 的文本。
<Border x:Class="CharacterMap.SymbolView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
RenderTransformOrigin="0.5, 0.5"
mc:Ignorable="d" Width="23"
Height="25" Background="White"
d:DesignHeight="300" d:DesignWidth="300"
BorderBrush="Black" BorderThickness="0 0 1 1">
<TextBlock Text="" x:Name="charcter" FontSize="17"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
所以现在,每次用户在组合框中选择字体系列时,我都会使用相应的符号更新这 150 个图块。我正在使用 Dispatcher 定时器来确保事情不会杀死 UI 线程。
private void Repaint(double value)
{
i = Convert.ToInt32((value / 0.1) * 15);
item_index = 0;
timer.Start();
}
在计时器的 tick 事件中,我正在更新图块,
void timer_Tick(object sender, EventArgs e)
{
try
{
SymbolView view = canvas.Children[item_index] as SymbolView;
int index = characterMap.Keys.ElementAt(i);
char c = Convert.ToChar(index);
view.charcter.Text = c.ToString();
item_index++;
i++;
}
catch (Exception)
{
SymbolView view = canvas.Children[item_index] as SymbolView;
view.charcter.Text = "";
item_index++;
i++;
}
if (item_index >= 150)
{
timer.Stop();
item_index = 0;
}
}
滚动
现在是时候处理滚动条了。由于我没有使用 WPF 项目控件,滚动条将不适用于我的情况。而且很明显,我们只会在 UI 中有 150 个图块。所以想法是,我们在显示符号的画布附近有一个ScrollBar
。基于滚动偏移量,整个图块使用更新的符号重新绘制。这项工作是,我们应该将滚动条偏移量与视图中的当前符号匹配。
基本的想法是,即使我们为字体系列获得了 20,000 个符号,我们只显示 150 个符号。在滚动时,我们将根据偏移量更新符号。
private void OnScroll(object sender, ScrollEventArgs e)
{
Repaint(e.NewValue);
}
private void Repaint(double value)
{
i = Convert.ToInt32((value / 0.1) * 15);
item_index = 0;
timer.Start();
}
所以现在我们有了一个不错的滚动效果,即使我们有大量的符号。我也添加了按键向下行为。您也可以使用键盘浏览符号。还有一个文本框用于选择和复制符号。
历史
1. 启用对滚动的实时更新。