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:
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)
{
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;
}
}
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