Click here to Skip to main content
11,493,948 members (58,474 online)
Click here to Skip to main content

Rich Text Box With Intellisense Ability

, 11 Apr 2011 Ms-PL 27.2K 4.8K 34
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)

Share

About the Author

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

Comments and Discussions

 
QuestionCould this technique be used if a word were used as the trigger instead of a character? Pin
Renee Cammarere9-Apr-15 10:42
memberRenee Cammarere9-Apr-15 10:42 
QuestionAdd control to VB project Pin
jonathansmr4-Mar-12 15:54
memberjonathansmr4-Mar-12 15:54 
QuestionHelp! *Specified Visual is already a child of another Visual or the root of a CompositionTarget.* ArgumentException was unhandled Pin
Rob Hurd27-Jan-12 4:26
memberRob Hurd27-Jan-12 4:26 
GeneralMy vote of 1 Pin
pisten24-Jan-12 4:39
memberpisten24-Jan-12 4:39 
GeneralRe: My vote of 1 Pin
zulu12-Mar-13 17:42
memberzulu12-Mar-13 17: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 | Terms of Use | Mobile
Web02 | 2.8.150520.1 | Last Updated 12 Apr 2011
Article Copyright 2011 by wnfk
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid