在c#windoes App中使Facebook自动完成像文本框一样 [英] Making Facebook Autocomplete like textbox in c# windoes App

查看:53
本文介绍了在c#windoes App中使Facebook自动完成像文本框一样的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



i想要创建一个winform文本框控件,就像Facebook自动完成文本框一样,这可以在网络应用程序的网络上找到,但我需要它在Windows中。

任何人都可以帮助我吗?



谢谢,

Mahesh

Hi,
i want to create a winform textbox control which works like a Facebook Autocomplete Textbox, this is available on net for web apps, but i need it in windows.
Can anyone help me ?

Thanks,
Mahesh

推荐答案

请查看以下链接

1) http://www.dotnetfunda.com/articles/article225 .aspx

2)在Windows中自动填充文本框c# [ ^ ]



让我知道是否需要任何帮助!!!



谢谢,


Akash Detroja
please check following link
1) http://www.dotnetfunda.com/articles/article225.aspx
2) Autocomplete textbox in windows c#[^]

Let me Know if need any help!!!

Thanks,

Akash Detroja


我使用devcomponents文本框作为Base,但它还有一个winform tekst框以及



I'm using the devcomponents textbox as Base but it shoul with a winform tekst box as well

namespace Controls
{
    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.Text;
    using System.Windows.Forms;

    public class autoCompleteLikeTextBoxX : DevComponents.DotNetBar.Controls.TextBoxX
    {
        #region Fields

        // the ListBox used for suggestions
        private System.Windows.Forms.ListBox myListBox;

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

        // a Panel for displaying
        private Panel panel;

        // max items for the "dropdown listbox/panel" like a combobox.
        private int _maxDropDownItems = 16;

        // Stores the height if the maximum number of items is used
        // used to check if there's enough room uder or above the control
        private int _maxHeight = 100;

        #endregion Fields
        #region Constructors

        // the constructor
        public autoCompleteLikeTextBoxX()
            : base()
        {
            // assigning some default values
            // minimum characters to be typed before suggestions are displayed
            this.MinTypedCharacters = 2;
            // not cases sensitive
            this.CaseSensitive = false;
            this.AccentSensitive = 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.myListBox = new ListBox();
            this.myListBox.Name = "SuggestionListBox";
            this.myListBox.Font = this.Font;
            this.myListBox.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;
            // At this moment the designer font isn't set, this is now done at the first time the control get's focus. 
            // 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(myListBox))
            {
                this.panel.Controls.Add(myListBox);
            }

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


            #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
            myListBox.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)
        [CategoryAttribute("Behavior")]
        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
        [CategoryAttribute("Behavior")]
        public bool CaseSensitive
        {
            get;
            set;
        }

        [CategoryAttribute("Behavior")]
        public bool AccentSensitive
        {
            get;
            set;
        }

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

        // the index selected in the listbox
        // maybe of intrest for other classes
        [Browsable(false)]
        public int SelectedIndex
        {
            get
            {
                return myListBox.SelectedIndex;
            }
            set
            {
                // musn't be null
                if (myListBox.Items.Count != 0)
                { myListBox.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()
        {

            if (_maxDropDownItems > 0)
            {

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

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

        }

        private int getStringHeight(string measureString)
        {
            Graphics e = this.myListBox.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);
                }
            }
        }


        // Some stuff needs the parent form to be initiated
        private bool _handlersSet;
        protected override void OnEnter(EventArgs e)
        {
            base.OnEnter(e);
            if (!_handlersSet)
            {
                this.myListBox.Font = this.Font;
                // handles resizing the form at the staty of a resize the panel will be hidden en is shows again after the resize
                this.ParentForm.ResizeBegin += new EventHandler(startResize);
                this.ParentForm.ResizeEnd += new EventHandler(endResize);
                _handlersSet = true;
                _selectOnLeave = false;
            }
        }

        /// <summary>
        /// indicates if the item must be selected on leaving the control
        /// </summary>
        private bool _selectOnLeave;
        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));
                _selectOnLeave = true;
                // work is done
                args.Handled = true;
            }
            // on key.down
            else if ((args.KeyCode == Keys.Down))
            {
                //move one down
                MoveSelectionInListBox((SelectedIndex + 1));
                _selectOnLeave = true;
                args.Handled = true;
            }
            else if ((args.KeyCode == Keys.PageUp))
            {
                //move 10 up
                MoveSelectionInListBox((SelectedIndex - 10));
                _selectOnLeave = true;
                args.Handled = true;
            }
            else if ((args.KeyCode == Keys.PageDown))
            {
                //move 10 down
                MoveSelectionInListBox((SelectedIndex + 10));
                _selectOnLeave = true;
                args.Handled = true;
            }
            // on enter
            else if ((args.KeyCode == Keys.Enter))
            {
                // select the item in the ListBox
                _selectOnLeave = true;
                SelectItem();
                args.Handled = true;
            }
            else
            {
                // work is not done, maybe the base class will process the event, so call it...
                base.OnKeyDown(args);
            }
        
           }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
    if (keyData == Keys.Tab) 
            {

                SelectItem();      
            }
        else if  (keyData == Keys.Enter)
            {
                    SelectItem();    
            }
    else if (keyData == (Keys.Tab | Keys.ShiftKey) | keyData == (Keys.Tab | Keys.Shift) | keyData == (Keys.Tab | Keys.LShiftKey) | keyData == (Keys.Tab | Keys.RShiftKey))
            {
                SelectItem();
            }
    else if (keyData == (Keys.Enter | Keys.ShiftKey) | keyData == (Keys.Enter | Keys.Shift) | keyData == (Keys.Enter | Keys.LShiftKey) | keyData == (Keys.Enter | Keys.RShiftKey))
            {
                SelectItem();
            }
        return base.ProcessCmdKey(ref msg, keyData);
        }





        // 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
                _selectOnLeave = true;
                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
            _selectOnLeave = true;
            SelectItem();
        }

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

        // event for DoubleClick in the ListBox
        private void listBox_Leave(object sender, EventArgs 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 > (myListBox.Items.Count - 1))
                {
                    SelectedIndex = (myListBox.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.myListBox.Items.Count > 0) && (this.SelectedIndex > -1) && _selectOnLeave))
            {
                // set the Text of the TextBox to the selected item of the ListBox
                // this.Text = this.listBox.SelectedItem.ToString();
                this.Text = myListBox.GetItemText(myListBox.SelectedItem);
                // 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

            // be casesensitive
            if (CaseSensitive)
            {

                if (AccentSensitive)
                {
                    foreach (string Str in AutoCompleteList)
                    {
                        // search for the substring (equal to SQL Like Command)
                        if ((Str.IndexOf(this.Text, StringComparison.Ordinal) > -1))
                        // Add candidates to new CurrentAutoCompleteList
                        { CurrentAutoCompleteList.Add(Str); }
                    }

                }
                else
                {
                    foreach (string Str in AutoCompleteList)
                    {
                        // search for the substring (equal to SQL Like Command)
                        //if ((Str.IndexOf(this.Text, StringComparison.Ordinal) > -1))
                        if (new String(Str.Trim().Normalize(NormalizationForm.FormD).Where(c => c < 128).ToArray()).IndexOf(new string(this.Text.Trim().Normalize(NormalizationForm.FormD).Where(c => c < 128).ToArray())) > -1)
                        // Add candidates to new CurrentAutoCompleteList
                        { CurrentAutoCompleteList.Add(Str); }
                    }
                }
            }
            // or ignore case
            else
            {
                if (AccentSensitive)
                {
                    foreach (string Str in AutoCompleteList)
                    {
                        // and search for the substring (equal to SQL Like Command)
                        if ((Str.ToLowerInvariant().IndexOf(this.Text.ToLowerInvariant(), StringComparison.OrdinalIgnoreCase) > -1))
                        { CurrentAutoCompleteList.Add(Str); }
                    }
                }
                else
                {
                    foreach (string Str in AutoCompleteList)
                    {
                        if (new String(Str.Trim().Normalize(NormalizationForm.FormD).Where(c => c < 128).ToArray()).ToLowerInvariant().IndexOf(new string(this.Text.Trim().Normalize(NormalizationForm.FormD).Where(c => c < 128).ToArray()).ToLowerInvariant()) > -1)
                        { CurrentAutoCompleteList.Add(Str); }
                    }
                }
            }



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

        // This is the most timecritical part, adding items to the ListBox
        private void UpdateListBoxItems()
        {


            // 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
                    try
                    {
                        this.ParentForm.Controls.Add(panel);
                    }
                    catch (Exception ex) { }
                }
                // 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)myListBox.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));
            }

        }

        // needed to determine where the panel will be placed and shown
        private Point GetLocationRelativeToForm(Control c)
        {
            Point locationOnForm = c.FindForm().PointToClient(c.Parent.PointToScreen(c.Location));
            return locationOnForm;
        }


        private void setPanelHeight(Panel pnl)
        {

            Point P;
            int listHeight;
            string currentList = "H\n";
            int availableBelow = 0; int availableAbove = 0;
            int AvailabelRows = 0;

            // If the max rows are 0 or less the maximum space on the form will be used
            if (_maxDropDownItems < 1)
            {
                P = GetLocationRelativeToForm(this);
                availableAbove = P.Y;
                availableBelow += this.ParentForm.Height - P.Y - this.Height;

                if (availableBelow > availableAbove)
                {
                    AvailabelRows = (int)availableBelow / RowHeight;
                    panel.Height = availableBelow;
                }
                else
                {
                    AvailabelRows = (int)availableAbove / RowHeight;
                    panel.Height = availableAbove;
                }

                if (CurrentAutoCompleteList.Count < AvailabelRows)
                {
                    for (int counter = 0; counter < CurrentAutoCompleteList.Count; counter += 1)
                    {
                        currentList += CurrentAutoCompleteList[counter] + "\n";
                    }
                    panel.Height = getStringHeight(currentList);
                }
            }
            else 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


        // Handle form resizing '
        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;
            }
        }

        //clean up the handlers at dispose.
        public virtual void Dispose()
        {
            this.ParentForm.ResizeBegin -= new EventHandler(startResize);
            this.ParentForm.ResizeEnd -= new EventHandler(endResize);
            base.Dispose(true);
            GC.SuppressFinalize(this);

        }
        #endregion Other
    }
}


这篇关于在c#windoes App中使Facebook自动完成像文本框一样的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆