Wpf and emoticons

How to display emoticons/emoji in a Wpf TextBox/TextBlock?

I made a test project to show how to do this (you can download it at the end of this post).
It is all about playing with Inlines in the TextBox’s FlowDocument and in the TextBlock.
The main code is this:

private static int FindFirstEmoticon(string text, int startIndex, out string emoticonFound)
{
  InitEmoticons();
  emoticonFound = string.Empty;
  int minIndex = -1;
  foreach (string e in m_Emoticons.Keys) {
    int index = text.IndexOf(e, startIndex);
    if (index >= 0) {
      if (minIndex < 0 || index < minIndex) {
        minIndex = index;
        emoticonFound = e;
      }
    }
  }
  return minIndex;
} // FindFirstEmoticon

public static void ParseText(FrameworkElement element)
{
  InitEmoticons();
  TextBlock textBlock = null;
  RichTextBox textBox = element as RichTextBox;
  if (textBox == null)
    textBlock = element as TextBlock;

  if (textBox == null && textBlock == null)
    return;

  if (textBox != null){
    FlowDocument doc = textBox.Document;
    for (int blockIndex=0; blockIndex < doc.Blocks.Count; blockIndex++){
      Block b = doc.Blocks.ElementAt(blockIndex);
      Paragraph p = b as Paragraph;
      if (p != null) {          
        ProcessInlines(textBox, p.Inlines);
      }
    }
  }else{
    ProcessInlines(null, textBlock.Inlines);
  }
} // ParseText

private static void ProcessInlines(RichTextBox textBox, InlineCollection inlines)
{
  for (int inlineIndex=0; inlineIndex < inlines.Count; inlineIndex++){
    Inline i = inlines.ElementAt(inlineIndex);
    if (i is Run) {
      Run r = i as Run;
      string text = r.Text;
      string emoticonFound = string.Empty;
      int index = FindFirstEmoticon(text, 0, out emoticonFound);
      if (index >= 0) {
        TextPointer tp = i.ContentStart;
        bool reposition = false;                
        while (!tp.GetTextInRun(LogicalDirection.Forward).StartsWith(emoticonFound)) 
          tp = tp.GetNextInsertionPosition(LogicalDirection.Forward);
        TextPointer end = tp;
        for (int j=0; j<emoticonFound.Length; j++)
          end = end.GetNextInsertionPosition(LogicalDirection.Forward);
        TextRange tr = new TextRange(tp, end);
        if (textBox != null)
          reposition = textBox.CaretPosition.CompareTo(tr.End) == 0;
        tr.Text = string.Empty;

        string imageFile = m_Emoticons[emoticonFound];
        Image image = new Image();
        BitmapImage bimg = new BitmapImage();
        bimg.BeginInit();
        bimg.UriSource = new Uri(imageFile, UriKind.Relative);
        bimg.EndInit();
        image.Source = bimg;
        image.Width = 24;

        InlineUIContainer iui = new InlineUIContainer(image, tp);
        iui.BaselineAlignment = BaselineAlignment.TextBottom;

        if (textBox != null && reposition)
          textBox.CaretPosition = tp.GetNextInsertionPosition(LogicalDirection.Forward);
      }
    }
  }
} // ProcessInlines

The code parses the current content of the TextBox/TextBlock and replaces the emoticons text (initialized int the InitEmoticons method) with the correct image.
If the element passed is a TextBox it also repositions the cursor in the correct position.

You can download the test project here.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.