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

Rich Text Box With Intellisense Ability

0.00/5 (No votes)
11 Apr 2011 1  
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 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