65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 中的字符映射表

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (8投票s)

2012年6月3日

CPOL

3分钟阅读

viewsIcon

51269

downloadIcon

2419

字符映射是 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. 启用对滚动的实时更新。

© . All rights reserved.