Introduction
The Character Map utility is free on all Windows machines and can be used to copy and paste accented
letters and other foreign language characters into any Windows application. The Character Map is similar to the Insert Symbol tool
found in some Windows applications such as Microsoft Word.
This article explains how to implement this tool using WPF with great performance. This tool can be easily integrated into any of your WPF applications easily.
Using the code
When I was start thinking about implementing this in WPF, I realized the main challenge would be the performance. But the native character map in Windows is really faster
and will give a nice user experience. So I am sure this article will be valid only if this tool would also give the same experience.
Getting the symbols
Let me first start with getting the symbols from Font files. Populating a ComboBox
with installed Font families is not a big deal in WPF.
The article
explains how to do that. Also the code is so simple.
<ComboBox ItemsSource="{x:Static Fonts.SystemFontFamilies}" />
To get the available symbols from a Typeface, first iterate through the typefaces in a Font family and choose the appropriate one. Once you got the Typeface, get the glyph
which gives you the character map dictionary.
IDictionary<int, ushort> characterMap;
foreach (Typeface typeface in font.GetTypefaces())
{
typeface.TryGetGlyphTypeface(out glyph);
if (glyph != null)
{
characterMap = glyph.CharacterToGlyphMap;
}
}
The variable characterMap
is a dictionary, which stores the unicode values for our symbols. So now we can go ahead and display the symbols in UI.
Symbols UI
As I previously stated, the performance will be a major bottle neck in WPF. Since some font families may have more than 20,000 symbols. In case if you like
to show them in a traditional ListBox with a wrap panel you would lose the user experience which Windows default character map has. I am sure there is a Virtualization
Wrap Panel for WPF posted in this code project article. But I am going
to use something better in which we don't need to care about the containers generation and disposing them.
I am going to use a Canvas and I decided my viewport size would be 345 X 250 and not more than that. Based on this I have placed 150 SymbolView
(view that holds
the symbol) objects into the canvas in horizontal wrap manner. Each view will have a textbox displaying the corresponding text of the symbol 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>
So now, everytime the user choose the Font family in the Combo Box, I will update the 150 tiles with corresponding symbols.
I am using a Dispatcher timer to ensure the things will not kill the UI thread.
private void Repaint(double value)
{
i = Convert.ToInt32((value / 0.1) * 15);
item_index = 0;
timer.Start();
}
In the tick event of the timer, I am updating the tiles,
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;
}
}
Scrolling
Now its time to handle the Scroll bar. Since I am not using the WPF Items Control, the scrollbars will not work for my case. And it is clear that we will be having only 150 tiles in the UI. So the idea is, we have a ScrollBar
near to the canvas showing symbols. Based on the scroll offset, the entire tiles are repainted with updated symbols. The work, is we should match the scrollbar offset to the current symbols in the view.
The base idea is, even though we got 20,000 symbols for a Font Family, we are showing only 150 symbols. On scrolling we will update the symbols based on the offset.
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();
}
So now we got a nice scrolling effect even though we have huge number of symbols. Also I have added the Key Down behavior. You could also navigate through the symbols using the Keyboard. A textbox is also there to select and copy the symbols.
History
1. Enable Live updates to scrolling.
Jawahar working as a Senior Development Engineer in Aditi Technologies,Bangalore, India. Specialist in all XAML frameworks. Very passionate on UX Design and Development. Skilled in Expression Blend, Design, WPF, Silverlight, Windows Phone 7/8, Windows 8. Good knowledge in Entity Framework, SQLite and SQL Server also. Also had good experience with PRISM, MVVM, Caliiburn Micro and other design patterns.
He developed few products for Syncfusion Inc. Also working on some freelancing projects. Worked as a lead developer of Metro Studio from Syncfusion Inc.
An active freelancer. http://xamlfactory.elance.com
http://about.me/jawahars
http://wpfplayground.com/