Click here to Skip to main content
Click here to Skip to main content

Rich Text Box With Intellisense Ability

, 11 Apr 2011
Rate this:
Please Sign up or sign in to vote.
By expanding RichTextBox, this article tries to show you a demo of RichTextBox with Intellisense, which is most like Visual studio, a powerful IDE. The custom control lets you add intellisense to your project in a much easier way.

Introduction

Days ago, I developed a small app in which there is a small functionality that can popup a list according to users input, which is most like Visual Studio IDE. This is a cool functionality which will make your app much more user-friendly. I extracted the code snippet and then built a custom control by expanding the RichTextBox class, and added some dependency properties to it, now you can use this custom control in your project, add intellisense easily.

The final result is as below:

intellisense_rich_text_box.png

How to Use the Control

Well, let's talk about how to use this custom control first. It is very very simple to add intellisense to your richtext box by this control. As you can see in the article later, I added two properties to the custom richtextbox, which are ContentAssistSource and ContentAssistTriggers. Let's see the XAML code first:

<rabbit:RichTextBoxEx   Name="richTextBoxEx1" 
 AutoAddWhiteSpaceAfterTriggered="{Binding IsChecked,ElementName=chkAutoAddWhitespace}" 
 ContentAssistTriggers="{Binding ContentAssistTriggers}"
 ContentAssistSource="{Binding ContentAssistSource}" />

Is it very very simple, right? You just need to bind two properties to the List in code-behind, the first is ContentAssistTriggers, which is the character list which would trigger the intellisense when user types the char to the rich text box, the second is ContentAssistSource, which is the item that will be used for intellisense.

How Can Intellisense be Implemented

How can intellisense be implemented here? First, we need to add a ListBox to the custom control, and add it to the rich text box's parent, which should be "Grid" here.

private ListBox AssistListBox = new ListBox();

void RichTextBoxEx_Loaded(object sender, RoutedEventArgs e)
{
     //init the assist list box
     if (this.Parent.GetType() != typeof(Grid))
     {
         throw new Exception("this control must be put in Grid control");
     }

     if (ContentAssistTriggers.Count == 0)
     {
         ContentAssistTriggers.Add(<a href="mailto:'@'">'@'</a>);
     }

     (this.Parent as Grid).Children.Add(AssistListBox);
      AssistListBox.MaxHeight = 100;
      AssistListBox.MinWidth = 100;
      AssistListBox.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
      AssistListBox.VerticalAlignment = System.Windows.VerticalAlignment.Top;
      AssistListBox.Visibility = System.Windows.Visibility.Collapsed;
      AssistListBox.MouseDoubleClick += 
	new MouseButtonEventHandler(AssistListBox_MouseDoubleClick);
      AssistListBox.PreviewKeyDown += new KeyEventHandler(AssistListBox_PreviewKeyDown);
}

As you can see above, we added some events to the ListBox, such as PreviewKeyDown and MouseDoubleClick, actually they handle the user's input when the intellisense pops up. You can find out what I do in the Event in my source code.

Then secondly, we should override the OnTextInput method of RichTextBox, which will be called when user inputs a character to the rich text box. In this method, we checked whether user has inputted the triggered character, if true, we will popup the intellisense, which actually is set the ListBox's visibility to Visible. As you can see in the following code snippet, we do not only show the ListBox, but also filter the content assist source according to user's input, and then set the Itemsource of ListBox to the filtered list.

protected override void OnTextInput(System.Windows.Input.TextCompositionEventArgs e)
{
    base.OnTextInput(e);
    if (IsAssistKeyPressed == false && e.Text.Length == 1)
    { 
        if (ContentAssistTriggers.Contains(char.Parse(e.Text)))
        {
            ResetAssistListBoxLocation();
            IsAssistKeyPressed = true;
            FilterAssistBoxItemsSource();
            return;
        }
    }

    if (IsAssistKeyPressed)
    {
        sbLastWords.Append(e.Text);
        FilterAssistBoxItemsSource();
    }
}

Thirdly, we should override the method OnPreviewKeyDown. In this method, we checked whether user pressed Enter, Space or Tab, if they pressed these keys and the content assist listbox is visible, insert the selected item, which actually is the string, to the rich text box.

protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)
{
    if (!IsAssistKeyPressed)
    {
        base.OnPreviewKeyDown(e);
        return;
    }
    
    ResetAssistListBoxLocation();
    
    if (e.Key == System.Windows.Input.Key.Back)
    {
        if (sbLastWords.Length > 0)
        {
            sbLastWords.Remove(sbLastWords.Length - 1, 1);
            FilterAssistBoxItemsSource();
        }
        else
        {
            IsAssistKeyPressed = false;
            sbLastWords.Clear();
            AssistListBox.Visibility = System.Windows.Visibility.Collapsed;
        }
    }

    //enter key pressed, insert the first item to richtextbox
    if ((e.Key == Key.Enter || e.Key == Key.Space || e.Key == Key.Tab))
    {
        AssistListBox.SelectedIndex = 0;
        if (InsertAssistWord())
        {
            e.Handled = true;
        }
    }

    if (e.Key == Key.Down)
    {
        AssistListBox.Focus();
    }

    base.OnPreviewKeyDown(e);
}

Until now, our custom rich text box has the ability of intellisense. You must have 
noticed that I called a method named FilterAssistBoxItemsSource, yes, it is one of the most important methods that helps to show the intellisense. Just look at the code:

private void FilterAssistBoxItemsSource()
{
    IEnumerable<string> temp = ContentAssistSource.Where
	(s => s.ToUpper().StartsWith(sbLastWords.ToString().ToUpper()));
    AssistListBox.ItemsSource = temp;
    AssistListBox.SelectedIndex = 0;
    if (temp.Count() == 0)
    {
        AssistListBox.Visibility = System.Windows.Visibility.Collapsed;
    }
    else
    {
        AssistListBox.Visibility = System.Windows.Visibility.Visible;
    }
}

History

  • 12th April, 2011: Initial post

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

About the Author

wnfk
Software Developer (Senior) Microsoft
China China
a software developer with great passion to programming.
Follow on   Twitter

Comments and Discussions

 
QuestionAdd control to VB project Pinmemberjonathansmr4-Mar-12 14:54 
QuestionHelp! *Specified Visual is already a child of another Visual or the root of a CompositionTarget.* ArgumentException was unhandled PinmemberRob Hurd27-Jan-12 3:26 
GeneralMy vote of 1 Pinmemberpisten24-Jan-12 3:39 
GeneralRe: My vote of 1 Pinmemberzulu12-Mar-13 16:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 12 Apr 2011
Article Copyright 2011 by wnfk
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid