Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Character Map in WPF

0.00/5 (No votes)
3 Jun 2012 1  
Character Map is a free utility found in Windows Machines. It is similar to the Insert Symbol tool in few MS Office applications. This article explains how to implement this tool using WPF.

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.  

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here