Click here to Skip to main content
15,891,136 members
Articles / Desktop Programming / Windows Forms

AutoComplete TextBox with SubString search, similar to SQL Like or Contains

Rate me:
Please Sign up or sign in to vote.
4.66/5 (26 votes)
12 Sep 2011CPOL3 min read 111.7K   11.9K   44   39
A TextBox with autocomplete capabilities in the manner of SQL's Like command
AutoCompleteTextBoxSample.jpg

Introduction

I was searching for a TextBox with autocomplete capabilities considering substring matches. The solutions I found were little clumsy, so here is my rather simple, but stable solution.

Background

This is my first article, so don't expect this to be perfect. The code comments are overkill, I think, but this makes the source self explaining.

Well, there are a few differences between other approaches. At first, we use a Panel instead of a Form to display a list of suggestions. Secondly, we use IndexOf instead of Linq to find the matches. Thirdly, we use pure safe .NET code only, no Win32 Calls and no sloppy threading, e.g. sleep(), or other stuff.

Behind the Scenes

In the main Form's Load event, we read a text file called "en-EN.dic", which is a dictionary with more than 50,000 entries. It is to be stored it in the component's AutoCompleteList property, which is a List<string>.

While the AutoCompleteList is used as "database" and remains unchanged, the CurrentAutoCompleteList property contains a subset of appropriate candidates to be shown as suggestions in a ListBox beneath.

The main work is done in a method called ShowSuggests() which calls a time critical method named UpdateCurrentAutoCompleteList() that calls the second time critical method UpdateListBoxItems(). I mention this because the internal list of elements to be shown and the list finally added to the image box are both time consuming operations that may cause laggy responses. So why are we using two lists for our data? Well, this is not the last word spoken, but I found DataSource/ DataContext to be faster than adding single items to the listbox in the substring query (see if ((Str.IndexOf(this.Text) > -1)) ).

Using the Code

The component is used like a normal TextBox, except that it has some "special" properties that can be set (CaseSensitive, MinTypedCharacters and the AutoCompleteList). A sample of the usage can be found in the Form's Load event. In brief: Drop it into a Form and assign a List<string> of phrases to the AutoCompleteList property.

Some Things to be Mentioned

I have done some performance measuring and alternative implementations, so you may switch between an ArrayList or a List<string> basis. I have chosen the second one because it is a generic type. However I found the ArrayList to perform a little better on large data (dictionary at about 10MB size). Maybe you would like to take this further, see the comments.

You will find two digressions, named excursions (bad English), like this in the source:

C#
#region Digression: Performance measuring of Linq queries
// This is a simple example of speedmeasurement for Linq queries
/*
CurrentAutoCompleteList.Clear();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
// using Linq query seems to be slower (twice as slow)
var query =
    from expression in this.AutoCompleteList
    where expression.ToLower().Contains(this.Text.ToLower())
    select expression;
foreach (string searchTerm in query)
{
    CurrentAutoCompleteList.Add(searchTerm);
}
stopWatch.Stop();
// method (see below) for printing the performance values to console
PrintStopwatch(stopWatch, "Linq - Contains");
*/
#endregion Digression: Performance measuring of Linq queries

The code within these regions is uncommented and meant for comparison of alternative implementations in the case shown above, to measure the performance of an alternative Linq query.

The other digression is about switching to a method using AddRange to fill the list of suggestions. In the example code, the default method used is a manual update of the BindingContext. If you experience problems with that, just feel free to choose the other approach.

Here is how the manual updating of the BindingContext of the ListBox works:

C#
// bind the data in the constructor
listBox.DataSource = CurrentAutoCompleteList;

// later on, use the CurrencyManager to update the BindingContext manually
((CurrencyManager)listBox.BindingContext[CurrentAutoCompleteList]).Refresh();
// note that Panel and ListBox have to be added to the ParentForm for this to work!!!

The rest is just about correct timing and knowing when to show components and how to handle key and mouse events for two components in one. So we take care of KeyDown for PageUp and PageDown keys, MouseClick and MouseDoubleClick events. And we ensure the component to fit into the ParentForm, avoid flickering and overlapping and so on.

Happy coding!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
SuggestionPerformance improvement Pin
Member 1564009425-May-22 21:06
Member 1564009425-May-22 21:06 
Questioncrash with own list Pin
Member 803001517-Dec-19 11:42
Member 803001517-Dec-19 11:42 
QuestionCan we apply the same code on datagridview Textbox column Pin
Member 1418692430-Aug-19 23:46
Member 1418692430-Aug-19 23:46 
GeneralMy vote of 5 Pin
Rickpat4-Apr-19 18:39
Rickpat4-Apr-19 18:39 
QuestionTy so much Pin
pekation28-May-18 8:23
pekation28-May-18 8:23 
QuestionError? And using it on Datagridview Pin
Member 119839076-Feb-18 23:41
Member 119839076-Feb-18 23:41 
QuestionAutoComplete with Key/Value Pair Pin
ugama14-Sep-16 3:52
ugama14-Sep-16 3:52 
AnswerTwo methods successful experience in the autoComplete textBox control with SQL Pin
Member 1113875416-Aug-16 1:39
Member 1113875416-Aug-16 1:39 
Questionhelp, convert to vb.net Pin
Member 115768855-Aug-16 9:16
Member 115768855-Aug-16 9:16 
QuestionBug Pin
krahmanali23-Dec-15 6:58
krahmanali23-Dec-15 6:58 
Question"Improvment" on class Pin
Member 120998942-Nov-15 1:38
Member 120998942-Nov-15 1:38 
Font change,
Max items property like comboboxes have.
Panel switches to above the textbox if there's not enough room below.

C#
namespace AutoCompleteTextBoxSample
{
    using System;
    using System.Collections;           // if you would like to use ArrayList insted
    using System.Collections.Generic;   // here we use Generic Type List<string>
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing;
    using System.Linq;
    using System.Windows.Forms;

    // the component is derived from a TextBox 
    // and is therfore called TextBox, but ment is this class (AutoCompleteTextbox)
    public class AutoCompleteTextbox : TextBox
    {
        #region Fields

        // the ListBox used for suggestions
        private ListBox listBox;

        // string to remember a former input
        private string oldText;

        // a Panel for displaying
        private Panel panel;

        private int _maxDropDownItems = 16;
        private int _maxHeight = 100;


   
        #endregion Fields


        #region Constructors

        // the constructor
        public AutoCompleteTextbox()
            : base()
        {
            // assigning some default values
            // minimum characters to be typed before suggestions are displayed
            this.MinTypedCharacters = 2;
            // not cases sensitive
            this.CaseSensitive = false;
            // the list for our suggestions database
            // the sample dictionary en-EN.dic is stored here when form1 is loaded (see form1.Load event)
            this.AutoCompleteList = new List<string>();

            // the listbox used for suggestions
            this.listBox = new ListBox();
            this.listBox.Name = "SuggestionListBox";
            this.listBox.Font = this.Font;
            this.listBox.Visible = true;
            this.MaxDropDownItems = 16;
            this.RowHeight = getStringHeight("H");
            // the panel to hold the listbox later on
            this.panel = new Panel();
            this.panel.Visible = false;
           // this.panel.Font = this.Font;
            // to be able to fit to changing sizes of the parent form
            this.panel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
            // initialize with minimum size to avoid overlaping or flickering problems
            this.panel.ClientSize = new System.Drawing.Size(1, 1);
            this.panel.Name = "SuggestionPanel";
            this.panel.Padding = new System.Windows.Forms.Padding(0, 0, 0, 0);
            this.panel.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0);
            this.panel.BackColor = Color.Transparent;
            this.panel.ForeColor = Color.Transparent;
            this.panel.Text = "";
            this.panel.PerformLayout();
            // add the listbox to the panel if not already done
            if (!panel.Controls.Contains(listBox))
            {
                this.panel.Controls.Add(listBox);
            }

            // make the listbox fill the panel
            this.listBox.Dock = DockStyle.Fill;
            // only one itme can be selected from the listbox
            this.listBox.SelectionMode = SelectionMode.One;
            // the events to be fired if an item is selected
            this.listBox.KeyDown += new KeyEventHandler(listBox_KeyDown);
            this.listBox.MouseClick += new MouseEventHandler(listBox_MouseClick);
            this.listBox.MouseDoubleClick += new MouseEventHandler(listBox_MouseDoubleClick);

            #region Excursus: ArrayList vs. List<string>
            // surpringly ArrayList is a little faster than List<string>
            // to use ArrayList instead, replace every 'List<string>' with 'ArrayList'
            // i will used List<string> cause it's generic type
            #endregion Excursus: ArrayList vs. List<string>
            // the list of suggestions actually displayed in the listbox
            // a subset of AutoCompleteList according to the typed in keyphrase
            this.CurrentAutoCompleteList = new List<string>();

            #region Excursus: DataSource vs. AddRange
            // using DataSource is faster than adding items (see
            // uncommented listBox.Items.AddRange method below)
            #endregion Excursus: DataSource vs. AddRange
            // Bind the CurrentAutoCompleteList as DataSource to the listbox
            listBox.DataSource = CurrentAutoCompleteList;

            // set the input to remember, which is empty so far
            oldText = this.Text;

        }

        #endregion Constructors

        #region Properties

        // maximumNumber of items to show (default = 16)
        [Browsable(true)]
        public int MaxDropDownItems
        {
            get
            {
                return _maxDropDownItems;
            }
            set
            {
                _maxDropDownItems = value;
                calculateMaxPanelHeight();

            }
        }

        private int RowHeight
        {
            get;
            set;
        }


        // the list for our suggestions database
        public List<string> AutoCompleteList
        {
            get;
            set;
        }

        // case sensitivity
         [Browsable(true)]
        public bool CaseSensitive
        {
            get;
            set;
        }

        // minimum characters to be typed before suggestions are displayed
        [Browsable(true)]
        public int MinTypedCharacters
        {
            get;
            set;
        }

        // the index selected in the listbox
        // maybe of intrest for other classes
        public int SelectedIndex
        {
            get
            {
                return listBox.SelectedIndex;
            }
            set
            {
                // musn't be null
                if (listBox.Items.Count != 0)
                { listBox.SelectedIndex = value; }
            }
        }

        // the actual list of currently displayed suggestions
        private List<string> CurrentAutoCompleteList
        {
            set;
            get;
        }

        // the parent Form of this control
        private Form ParentForm
        {
            get { return this.Parent.FindForm(); }
        }

        #endregion Properties

        #region Methods


        public void calculateMaxPanelHeight()
        {

            // one element extra beacuse the typed value can be present as well.
            string measureString = "H\n";
            Graphics e = this.listBox.CreateGraphics();

            for (int counter = 1 ; counter < _maxDropDownItems; counter++)
            {
                measureString +=  "H\n";
            }
            _maxHeight = getStringHeight(measureString);
             
        }


        private int getStringHeight(string measureString)
        {
            Graphics e = this.listBox.CreateGraphics();

            Font stringFont = this.Font;

            // Measure string.
            SizeF stringSize = new SizeF();
            stringSize = e.MeasureString(measureString, stringFont);  

            e.Dispose();

            return (int) stringSize.Height;
        }

        // hides the listbox
        public void HideSuggestionListBox()
        {
            if ((ParentForm != null))
            {
                // hiding the panel also hides the listbox
                panel.Hide();
                // now remove it from the ParentForm (Form1 in this example)
                if (this.ParentForm.Controls.Contains(panel))
                {
                    this.ParentForm.Controls.Remove(panel);
                }
            }
        }

        private bool _handlersSet;
        protected override void OnEnter(EventArgs e)
        {
            base.OnEnter(e);

            if(!_handlersSet)
            {

                this.panel.Font = this.Font;
                this.listBox.Font = this.Font;
                this.panel.Refresh();
                this.panel.PerformLayout();
                this.ParentForm.ResizeBegin += new EventHandler(startResize);
                this.ParentForm.ResizeEnd += new EventHandler(endResize);
                _handlersSet = true;

            }
           
        }

        protected override void OnKeyDown(KeyEventArgs args)
        {
            // if user presses key.up
            if ((args.KeyCode == Keys.Up))
            {
                // move the selection in listbox one up
                MoveSelectionInListBox((SelectedIndex - 1));
                // work is done
                args.Handled = true;
            }
            // on key.down
            else if ((args.KeyCode == Keys.Down))
            {
                //move one down
                MoveSelectionInListBox((SelectedIndex + 1));
                args.Handled = true;
            }
            else if ((args.KeyCode == Keys.PageUp))
            {
                //move 10 up
                MoveSelectionInListBox((SelectedIndex - 10));
                args.Handled = true;
            }
            else if ((args.KeyCode == Keys.PageDown))
            {
                //move 10 down
                MoveSelectionInListBox((SelectedIndex + 10));
                args.Handled = true;
            }
            // on enter
            else if ((args.KeyCode == Keys.Enter))
            {
                // select the item in the ListBox
                SelectItem();
                args.Handled = true;
            }
            else
            {
                // work is not done, maybe the base class will process the event, so call it...
                base.OnKeyDown(args);
            }
        }

        // if the user leaves the TextBox, the ListBox and the panel ist hidden
        protected override void OnLostFocus(System.EventArgs e)
        {
            if (!panel.ContainsFocus)
            {
                // call the baseclass event
                base.OnLostFocus(e);
                // then hide the stuff
                this.HideSuggestionListBox();
            }
        }

        // if the input changes, call ShowSuggests()
        protected override void OnTextChanged(EventArgs args)
        {
            // avoids crashing the designer
            if (!this.DesignMode)
                ShowSuggests();
            base.OnTextChanged(args);
            // remember input
            oldText = this.Text;
        }

        
        // event for any key pressed in the ListBox
        private void listBox_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            // on enter
            if (e.KeyCode == Keys.Enter)
            {
                // select the current item
                SelectItem();
                // work done
                e.Handled = true;
            }
        }

        // event for MouseClick in the ListBox
        private void listBox_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            // select the current item
            SelectItem();
        }

        // event for DoubleClick in the ListBox
        private void listBox_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            // select the current item
            SelectItem();
        }

        private void MoveSelectionInListBox(int Index)
        {
            // beginning of list
            if (Index <= -1)
            { this.SelectedIndex = 0; }
            else
                // end of liste
                if (Index > (listBox.Items.Count - 1))
                {
                    SelectedIndex = (listBox.Items.Count - 1);
                }
                else
                // somewhere in the middle
                { SelectedIndex = Index; }
        }

        // selects the current item
        private bool SelectItem()
        {
            // if the ListBox is not empty
            if (((this.listBox.Items.Count > 0) && (this.SelectedIndex > -1)))
            {
                // set the Text of the TextBox to the selected item of the ListBox
                this.Text = this.listBox.SelectedItem.ToString();
                // and hide the ListBox
                this.HideSuggestionListBox();
            }
            return true;
        }

        // shows the suggestions in ListBox beneath the TextBox
        // and fitting it into the ParentForm
        private void ShowSuggests()
        {
            // show only if MinTypedCharacters have been typed
            if (this.Text.Length >= MinTypedCharacters)
            {
                // prevent overlapping problems with other controls
                // while loading data there is nothing to draw, so suspend layout
                panel.SuspendLayout();
                // user is typing forward, char has been added at the end of the former input
                if ((this.Text.Length > 0) && (this.oldText == this.Text.Substring(0, this.Text.Length - 1)))
                {
                    //handle forward typing with refresh
                    UpdateCurrentAutoCompleteList();
                }
                // user is typing backward - char bas been removed
                else if ((this.oldText.Length > 0) && (this.Text == this.oldText.Substring(0, this.oldText.Length - 1)))
                {
                    //handle backward typing with refresh
                    UpdateCurrentAutoCompleteList();
                }
                // something within has changed
                else
                {
                    // handle other things like corrections in the middle of the input, clipboard pastes, etc. with refresh
                    UpdateCurrentAutoCompleteList();
                }

                if (((CurrentAutoCompleteList != null) && CurrentAutoCompleteList.Count > 0))
                {
                    // finally show Panel and ListBox
                    // (but after refresh to prevent drawing empty rectangles)
                    panel.Show();
                    // at the top of all controls
                    panel.BringToFront();
                    // then give the focuse back to the TextBox (this control)
                    this.Focus();
                }
                // or hide if no results
                else
                {
                    this.HideSuggestionListBox();
                }
                // prevent overlapping problems with other controls
                panel.ResumeLayout(true);
            }
            // hide if typed chars <= MinCharsTyped
            else
            {
                this.HideSuggestionListBox();
            }
        }

        // This is a timecritical part
        // Fills/ refreshed the CurrentAutoCompleteList with appropreate candidates
        private void UpdateCurrentAutoCompleteList()
        {
            // the list of suggestions has to be refreshed so clear it
            CurrentAutoCompleteList.Clear();
            // an find appropreate candidates for the new CurrentAutoCompleteList in AutoCompleteList
            foreach (string Str in AutoCompleteList)
            {
                // be casesensitive
                if (CaseSensitive)
                {
                    // search for the substring (equal to SQL Like Command)
                    if ((Str.IndexOf(this.Text) > -1))
                    // Add candidates to new CurrentAutoCompleteList
                    { CurrentAutoCompleteList.Add(Str); }
                }
                // or ignore case
                else
                {
                    // and search for the substring (equal to SQL Like Command)
                    if ((Str.ToLower().IndexOf(this.Text.ToLower()) > -1))
                    // Add candidates to new CurrentAutoCompleteList
                    { CurrentAutoCompleteList.Add(Str); }
                }
            }
            #region Excursus: Performance measuring of Linq queries
            // This is a simple example of speedmeasurement for Linq querries
            /*
            CurrentAutoCompleteList.Clear();
            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();
            // using Linq query seems to be slower (twice as slow)
            var query =
                from expression in this.AutoCompleteList
                where expression.ToLower().Contains(this.Text.ToLower())
                select expression;
            foreach (string searchTerm in query)
            {
                CurrentAutoCompleteList.Add(searchTerm);
            }
            stopWatch.Stop();
            // method (see below) for printing the performance values to console
            PrintStopwatch(stopWatch, "Linq - Contains");
            */
            #endregion Excursus: Performance measuring of Linq queries

            // countinue to update the ListBox - the visual part
            UpdateListBoxItems();
        }

        // This is the most timecritical part, adding items to the ListBox
        private void UpdateListBoxItems()
        {
            #region Excursus: DataSource vs. AddRange
            /*
                    // This part is not used due to 'listBox.DataSource' approach (see constructor)
                    // left for comparison, delete for productive use
                    listBox.BeginUpdate();
                    listBox.Items.Clear();
                    //Fills the ListBox
                    listBox.Items.AddRange(this.CurrentAutoCompleteList.ToArray());
                    listBox.EndUpdate();
                    // to use this method remove the following
                    // "((CurrencyManager)listBox.BindingContext[CurrentAutoCompleteList]).Refresh();" line and
                    // "listBox.DataSource = CurrentAutoCompleteList;" line from the constructor
                    */
            #endregion Excursus: DataSource vs. AddRange

            // if there is a ParentForm
            if ((ParentForm != null))
            {
                 // get its width
                panel.Width = this.Width;
                // calculate the remeining height beneath the TextBox
                setPanelHeight(panel);
                // and the Location to use
                setPanelPosition(panel);  
                //panel.Location = this.Location + new Size(0, this.Height);
                
                // Panel and ListBox have to be added to ParentForm.Controls before calling BingingContext
                if (!this.ParentForm.Controls.Contains(panel))
                {
                    // add the Panel and ListBox to the PartenForm
                    this.ParentForm.Controls.Add(panel);
                }
                // Update the listBox manually - List<string> dosn't support change events
                // this is the DataSource approche, this is a bit tricky and may cause conflicts,
                // so in case fall back to AddRange approache (see Excursus)
                ((CurrencyManager)listBox.BindingContext[CurrentAutoCompleteList]).Refresh();
            }
        }


        /// <summary>
        /// Decides if the panel is placed below or above the textbox,
        /// depanding on the available space on the form
        /// </summary>
        /// <param name="panel"></param>
        private void setPanelPosition(Panel panel)
        {
            int availableBelow = 0; int availableAbove = 0;
            Point P;
            P = GetLocationRelativeToForm(this);


            availableAbove =  P.Y;
            availableBelow +=  this.ParentForm.Height -  P.Y - this.Height;

           
            if (availableBelow > panel.Height)
            {
                panel.Location = P + new Size(0, this.Height )  ;
            }
            else if ( availableAbove > panel.Height)
            {
                panel.Location = new Point(P.X, P.Y - panel.Height + (int)((_maxDropDownItems - (panel.Height / RowHeight)) / 3));
            }
            else if (availableBelow > availableAbove)
            {
            panel.Height = availableBelow;
            panel.Location = P + new Size(0, this.Height);
            }
            else
            {

            // a corection is needed 

            panel.Height = availableAbove;
            panel.Location = new Point( P.X, P.Y - panel.Height + (int)((_maxDropDownItems  -(panel.Height/RowHeight))/3));
            }

        }

        private Point GetLocationRelativeToForm(Control c)
        {
            // Method 1: walk up the control tree
            //Point controlLocationRelativeToForm1 = new Point();
            //Control currentControl = c;
            //while (currentControl.Parent != null)
            //{
            //    controlLocationRelativeToForm1.Offset(currentControl.Left, currentControl.Top);
            //    currentControl = currentControl.Parent;
            //}

            //// Method 2: determine absolute position on screen of control and form, and calculate difference
            //Point controlScreenPoint = c.PointToScreen(Point.Empty);
            //Point formScreenPoint = PointToScreen(Point.Empty);
            //Point controlLocationRelativeToForm2 = controlScreenPoint - new Size(formScreenPoint);

            // Method 3: combine PointToScreen() and PointToClient()
            Point locationOnForm = c.FindForm().PointToClient(c.Parent.PointToScreen(c.Location));

          

            return locationOnForm;
        }



        private void setPanelHeight (Panel pnl)
        {

            int listHeight;
            string currentList = "H\n";


            if ( CurrentAutoCompleteList.Count < _maxDropDownItems)
            {

                if (CurrentAutoCompleteList.Count > 0 )
                {
                     for (int counter = 0; counter < CurrentAutoCompleteList.Count; counter += 1)
                    {
                        currentList += CurrentAutoCompleteList[counter] + "\n";
                    } 
                    listHeight = getStringHeight(currentList);
                    if (listHeight < _maxHeight && listHeight > 0)
                    {
                        panel.Height = listHeight;
                    }
                    else
                    { 
                        panel.Height = 0;
                    }

                }
            }
            else
            {
                panel.Height = _maxHeight;
            }
            
        }

        #endregion Methods

        #region Other


        private bool resizing;

        private void startResize(Object sender , EventArgs e)
        {
            if (panel.Visible)
            {
                resizing = true;
                panel.Visible = false;
            }
        }


        private void endResize(Object sender, EventArgs e)
        {
            if (resizing)
            {
                resizing = false;
                panel.Width = this.Width;
                setPanelHeight(panel);
                setPanelPosition(panel);
                panel.Visible = true;
            }
        }


        /*
        // only needed for performance measuring - delete for productional use
        private void PrintStopwatch(Stopwatch stopWatch, string comment)
        {
            // Get the elapsed time as a TimeSpan value.
            TimeSpan ts = stopWatch.Elapsed;
            // Format and display the TimeSpan value.
            string elapsedTime = String.Format("{0:00}h:{1:00}m:{2:00},{3:000}s \t {4}",
                ts.Hours, ts.Minutes, ts.Seconds,
                ts.Milliseconds, comment);
            Console.WriteLine("RunTime " + elapsedTime);
        }
        */

        public virtual void Dispose()
        {
            this.ParentForm.ResizeBegin -= new EventHandler(startResize);
            this.ParentForm.ResizeEnd -= new EventHandler(endResize);
            base.Dispose(true);
            GC.SuppressFinalize(this);

        }
        #endregion Other
    }
}

QuestionDatagridview textbox column Pin
Member 84196013-Mar-15 1:28
Member 84196013-Mar-15 1:28 
GeneralMy vote of 5 Pin
Member 1146617619-Feb-15 22:30
Member 1146617619-Feb-15 22:30 
QuestionWhat is the Point of this If Block? Pin
SkiGeek8216-Dec-14 14:22
SkiGeek8216-Dec-14 14:22 
AnswerRe: What is the Point of this If Block? Pin
Oliver Bleckmann18-Dec-14 23:45
Oliver Bleckmann18-Dec-14 23:45 
GeneralMy vote of 1 Pin
agent_kruger2-Oct-14 0:19
professionalagent_kruger2-Oct-14 0:19 
GeneralRe: My vote of 1 Pin
Oliver Bleckmann3-Oct-14 5:26
Oliver Bleckmann3-Oct-14 5:26 
GeneralRe: My vote of 1 Pin
agent_kruger21-Oct-14 4:14
professionalagent_kruger21-Oct-14 4:14 
GeneralRe: My vote of 1 Pin
Oliver Bleckmann27-Nov-14 13:20
Oliver Bleckmann27-Nov-14 13:20 
GeneralRe: My vote of 1 Pin
Eddy Vluggen12-Jun-15 0:25
professionalEddy Vluggen12-Jun-15 0:25 
QuestionBug when AutoCompleteTextBox are inside tabcontrol Pin
Member 108523911-Aug-14 12:13
Member 108523911-Aug-14 12:13 
AnswerRe: Bug when AutoCompleteTextBox are inside tabcontrol Pin
Oliver Bleckmann4-Aug-14 9:05
Oliver Bleckmann4-Aug-14 9:05 
GeneralRe: Bug when AutoCompleteTextBox are inside tabcontrol Pin
Member 108523915-Aug-14 4:38
Member 108523915-Aug-14 4:38 
GeneralRe: Bug when AutoCompleteTextBox are inside tabcontrol Pin
Oliver Bleckmann6-Aug-14 1:13
Oliver Bleckmann6-Aug-14 1:13 
BugRe: Bug when AutoCompleteTextBox are inside tabcontrol Pin
Member 131138085-Sep-18 3:46
Member 131138085-Sep-18 3:46 

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

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