vbAccelerator - Contents of code file: RichEditAutoComplete_AutoComplete.cs

using System;
using System.Drawing;
using System.Windows.Forms;

namespace RichEditAutoComplete
{
   /// <summary>
   /// A rudimentary class to demonstrate how an auto-complete IDE can be 
   /// created using a RichTextBox and a DropDown combo box. 
   /// More sophisticated varities of this can be designed if you
   /// also implement <see cref="IMessageFilter"/>.
   /// </summary>
   public class AutoComplete
   {

      private bool dropDownActive = false;
      private int selIndex = -1;
      private int lastLength = 0;
      private int lastTextLength = 0;
      private DropDown comboBox = null;
      private RichTextBox textBox = null;
      private EventHandler comboCloseUpHandler = null;
      private KeyPressEventHandler comboKeyPressHandler = null;


      /// <summary>
      /// Responds to KeyPress arguments in the combo box.
      /// </summary>
      /// <param name="sender">ComboBox which received the key press</param>
      /// <param name="e">Details of the key press</param>
      private void comboBox_KeyPress( object sender, KeyPressEventArgs e )
      {
         // does the typed text match anything?
         String text = comboBox.Text;

         Console.WriteLine(text + "," + e.KeyChar);
         if (e.KeyChar == 8)
         {
            if (text.Length > 0)
            {
               if (text.Length == lastTextLength)
               {
                  text = text.Substring(0, text.Length - 1);
                  comboBox.Text = text;
               }
            }
            else
            {
               // backspace with no text, time 
               // to stop:
               comboBox.SelectedIndex = -1;
               comboBox.DroppedDown = false;
               return;
            }
         }
         Console.WriteLine("'" + text + "'");

         int findIndex = comboBox.FindString(text);
         
         if (findIndex > -1) 
         {
            if (comboBox.SelectedIndex != findIndex)
            {
               comboBox.SelectedIndex = findIndex;         
               comboBox.SelectionStart = text.Length;
               if (text.Length < comboBox.Items[findIndex].ToString().Length)
               {
                  comboBox.SelectionLength =
                   comboBox.Items[findIndex].ToString().Length - text.Length;
               }
            }
         }
         lastTextLength = text.Length;
         RenderText(text);

         if (e.KeyChar == 46)
         {
            // deleted the first character, stop auto-complete
            comboBox.SelectedIndex = -1;
            comboBox.DroppedDown = false;
         }

      }

      /// <summary>
      /// Responds to the ComboBox close up event.
      /// </summary>
      /// <param name="sender">ComboBox which has closed up.</param>
      /// <param name="e">Not used.</param>
      private void comboBox_CloseUp(object sender, EventArgs e)
      {   
         if (this.dropDownActive)
         {
            Stop();
            if (comboBox.SelectedIndex > -1)
            {
               RenderText(comboBox.SelectedItem.ToString());
            }
            textBox.Focus();
         }
      }

      /// <summary>
      /// Writes the specified text into the 
      /// RichEdit box at the current auto-complete location.
      /// </summary>
      /// <param name="text">Text to write</param>
      private void RenderText(String text)
      {
         textBox.Select(selIndex, lastLength);
         textBox.SelectedText = text;
         lastLength = text.Length;
         textBox.Select(selIndex + lastLength, 0);
      }

      /// <summary>
      /// Starts Auto-Complete processing.  Call on response to the user
      /// typing something which warrants auto-complete.
      /// </summary>
      /// <param name="text">RichTextBox which is being auto-completed
       in.</param>
      /// <param name="combo">DropDown combo box to show</param>
      public void Start(RichTextBox text, DropDown combo)
      {
         // Store reference to the controls
         comboBox = combo;
         textBox = text;

         // Install events needed to track auto-completion
         comboCloseUpHandler = new EventHandler(comboBox_CloseUp);
         comboBox.CloseUp += comboCloseUpHandler;
         comboKeyPressHandler = new KeyPressEventHandler(comboBox_KeyPress);
         comboBox.KeyPress += comboKeyPressHandler;

         // Initialise the auto-complete text
         comboBox.Text = "";
         this.selIndex = textBox.SelectionStart;
         this.lastLength = 0;
         this.dropDownActive = true;         

         // Get the position of selected character:
         int selIndex = textBox.SelectionStart;
         Point location = textBox.GetPositionFromCharIndex(selIndex);
         // make position relative to the screen:
         location = textBox.PointToScreen(location);
         // Add the height of a line based on the rich text box overall font
         Graphics gfx = Graphics.FromHwnd(textBox.Handle);
         SizeF sz = gfx.MeasureString("Xg", textBox.Font, 512);
         gfx.Dispose();
         location.Y += (int) sz.Height;
         comboBox.DropDownLocation = location;

         // Set to a suitable cursor:
         textBox.Cursor = Cursors.Arrow;

         // Show the drop-down:
         comboBox.DroppedDown = true;
         comboBox.Focus();         
         
      }

      /// <summary>
      /// Gets whether the Auto-Complete drop down is active or not.
      /// </summary>
      public bool Active
      {
         get
         {
            return this.dropDownActive;
         }
      }

      /// <summary>
      /// Stops auto-complete processing. Called automatically
      /// when the combo box is closed (e.g. Escape, Return etc)
      /// </summary>
      public void Stop()
      {
         if (this.dropDownActive)
         {
            this.dropDownActive = false;
            comboBox.CloseUp -= comboCloseUpHandler;
            comboBox.KeyPress -= comboKeyPressHandler;
            textBox.Cursor = Cursors.Default;
         }
      }


      /// <summary>
      /// Constructor
      /// </summary>
      public AutoComplete()
      {
         // intentionally blank
      }
   }


}