的WinForms | C#|自动完成在一个文本框的中间? [英] WinForms | C# | AutoComplete in the Middle of a Textbox?

查看:116
本文介绍了的WinForms | C#|自动完成在一个文本框的中间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个文本框,做自动完成,像这样:

  txtName.AutoCompleteMode = AutoCompleteMode.Suggest;
txtName.AutoCompleteSource = AutoCompleteSource.CustomSource;
txtName.AutoCompleteCustomSource = namesCollection;

它的工作原理,但仅在文本框的开头。我想自动完成踢在用户输入任何文字,在文本框中的任何位置。


解决方案

 使用系统;
使用System.Collections.Generic;
使用System.Drawing中;
使用System.Windows.Forms的;命名空间TubeUploader
{
    公共类AutoCompleteTextBox:文本框
    {
        私人列表框_listBox;
        私人布尔_isAdded;
        私有String [] _​​values​​;
        私人字符串_formerValue =的String.Empty;        公共AutoCompleteTextBox()
        {
            的InitializeComponent();
            ResetListBox();
        }        私人无效的Ini​​tializeComponent()
        {
            _listBox =新的ListBox();
            的KeyDown + = this_KeyDown;
            的KeyUp + = this_KeyUp;
        }        私人无效ShowListBox()
        {
            如果(!_isAdded)
            {
                Parent.Controls.Add(_listBox);
                _listBox.Left =左;
                _listBox.Top =上衣+高度;
                _isAdded = TRUE;
            }
            _listBox.Visible = TRUE;
            _listBox.BringToFront();
        }        私人无效ResetListBox()
        {
            _listBox.Visible = FALSE;
        }        私人无效this_KeyUp(对象发件人,发送KeyEventArgs E)
        {
            UpdateListBox();
        }        私人无效this_KeyDown(对象发件人,发送KeyEventArgs E)
        {
            开关(e.Key code)
            {
                案例Keys.Tab:
                    {
                        如果(_listBox.Visible)
                        {
                            InsertWord((字符串)_listBox.SelectedItem);
                            ResetListBox();
                            _formerValue =文本;
                        }
                        打破;
                    }
                案例Keys.Down:
                    {
                        如果((_listBox.Visible)及及(_listBox.SelectedIndex&下; _listBox.Items.Count - 1))
                            _listBox.SelectedIndex ++;                        打破;
                    }
                案例Keys.Up:
                    {
                        如果((_listBox.Visible)及及(_listBox.SelectedIndex大于0))
                            _listBox.SelectedIndex--;                        打破;
                    }
            }
        }        保护覆盖布尔IsInputKey(钥匙KEYDATA)
        {
            开关(KEYDATA)
            {
                案例Keys.Tab:
                    返回true;
                默认:
                    返回base.IsInputKey(KEYDATA);
            }
        }        私人无效UpdateListBox()
        {
            如果(文字== _formerValue)回报;
            _formerValue =文本;
            串词=朗朗上口();            如果(_values​​ =空&放大器;!&放大器; word.Length大于0)
            {
                的String [] =匹配Array.FindAll(_values​​,
                                                 X => (x.StartsWith(文字,StringComparison.OrdinalIgnoreCase)及和放大器;!SelectedValues​​.Contains(X)));
                如果(matches.Length大于0)
                {
                    ShowListBox();
                    _listBox.Items.Clear();
                    Array.ForEach(比赛中,x => _listBox.Items.Add(X));
                    _listBox.SelectedIndex = 0;
                    _listBox.Height = 0;
                    _listBox.Width = 0;
                    焦点();
                    使用(图形图像= _listBox.CreateGraphics())
                    {
                        的for(int i = 0; I< _listBox.Items.Count;我++)
                        {
                            _listBox.Height + = _listBox.GetItemHeight(ⅰ);
                            //它项宽度是比当前的大
                            //将其设置为新的最大宽度项
                            // GetItemRectangle不为我工作
                            //我们通过添加一些额外的空间,_
                            INT itemWidth =(int)的graphics.MeasureString(((字符串)_listBox.Items [I])+__listBox.Font).WIDTH;
                            _listBox.Width =(_listBox.Width< itemWidth)? itemWidth:_listBox.Width;
                        }
                    }
                }
                其他
                {
                    ResetListBox();
                }
            }
            其他
            {
                ResetListBox();
            }
        }        私人字符串朗朗上口()
        {
            字符串文本=文本;
            INT POS = SelectionStart;            INT posStart = text.LastIndexOf('',(正 - 。1)?0:POS - 1);
            posStart =(posStart == -1)? 0:posStart + 1;
            INT posEnd = text.IndexOf('',POS机);
            posEnd =(posEnd == -1)? text.Length:posEnd;            INT长度=((posEnd - posStart)小于0)? 0:posEnd - posStart;            返回text.Substring(posStart,长度);
        }        私人无效InsertWord(字符串newTag)
        {
            字符串文本=文本;
            INT POS = SelectionStart;            INT posStart = text.LastIndexOf('',(正 - 。1)?0:POS - 1);
            posStart =(posStart == -1)? 0:posStart + 1;
            INT posEnd = text.IndexOf('',POS机);            串firstPart = text.Substring(0,posStart)+ newTag;
            字符串updatedText = firstPart +(?(posEnd == -1):text.Substring(posEnd,text.Length - posEnd));
            文本= updatedText;
            SelectionStart = firstPart.Length;
        }        公众的String []值
        {
            得到
            {
                返回_values​​;
            }
            组
            {
                _values​​ =价值;
            }
        }        公开名单<串GT; SelectedValues
        {
            得到
            {
                的String []结果= Text.Split(新[] {''},StringSplitOptions.RemoveEmptyEntries);
                返回新的List<串GT;(结果);
            }
        }    }}

用法示例

 使用系统;
使用System.Windows.Forms的;命名空间自动完成
{
    公共部分类TESTFORM:表单
    {
        私人只读的String [] = _values​​ {一,二,三化,树,四有,fivee};        公共TESTFORM()
        {
            的InitializeComponent();
            //自动完成是我们在表格上的特殊文本框控件
            AutoComplete.Values​​ = _values​​;
        }    }
}

I have a textbox that does autocompletion like so:

txtName.AutoCompleteMode = AutoCompleteMode.Suggest;
txtName.AutoCompleteSource = AutoCompleteSource.CustomSource;
txtName.AutoCompleteCustomSource = namesCollection;

It works, but only at the beginning of a textbox. I'd like autocomplete to kick in for any word the user is entering, at any position in the textbox.

解决方案

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace TubeUploader
{
    public class AutoCompleteTextBox : TextBox
    {
        private ListBox _listBox;
        private bool _isAdded;
        private String[] _values;
        private String _formerValue = String.Empty;

        public AutoCompleteTextBox()
        {
            InitializeComponent();
            ResetListBox();
        }

        private void InitializeComponent()
        {
            _listBox = new ListBox();
            KeyDown += this_KeyDown;
            KeyUp += this_KeyUp;
        }

        private void ShowListBox()
        {
            if (!_isAdded)
            {
                Parent.Controls.Add(_listBox);
                _listBox.Left = Left;
                _listBox.Top = Top + Height;
                _isAdded = true;
            }
            _listBox.Visible = true;
            _listBox.BringToFront();
        }

        private void ResetListBox()
        {
            _listBox.Visible = false;
        }

        private void this_KeyUp(object sender, KeyEventArgs e)
        {
            UpdateListBox();
        }

        private void this_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Tab:
                    {
                        if (_listBox.Visible)
                        {
                            InsertWord((String)_listBox.SelectedItem);
                            ResetListBox();
                            _formerValue = Text;
                        }
                        break;
                    }
                case Keys.Down:
                    {
                        if ((_listBox.Visible) && (_listBox.SelectedIndex < _listBox.Items.Count - 1))
                            _listBox.SelectedIndex++;

                        break;
                    }
                case Keys.Up:
                    {
                        if ((_listBox.Visible) && (_listBox.SelectedIndex > 0))
                            _listBox.SelectedIndex--;

                        break;
                    }
            }
        }

        protected override bool IsInputKey(Keys keyData)
        {
            switch (keyData)
            {
                case Keys.Tab:
                    return true;
                default:
                    return base.IsInputKey(keyData);
            }
        }

        private void UpdateListBox()
        {
            if (Text == _formerValue) return;
            _formerValue = Text;
            String word = GetWord();

            if (_values != null && word.Length > 0)
            {
                String[] matches = Array.FindAll(_values,
                                                 x => (x.StartsWith(word, StringComparison.OrdinalIgnoreCase) && !SelectedValues.Contains(x)));
                if (matches.Length > 0)
                {
                    ShowListBox();
                    _listBox.Items.Clear();
                    Array.ForEach(matches, x => _listBox.Items.Add(x));
                    _listBox.SelectedIndex = 0;
                    _listBox.Height = 0;
                    _listBox.Width = 0;
                    Focus();
                    using (Graphics graphics = _listBox.CreateGraphics())
                    {
                        for (int i = 0; i < _listBox.Items.Count; i++)
                        {
                            _listBox.Height += _listBox.GetItemHeight(i);
                            // it item width is larger than the current one
                            // set it to the new max item width
                            // GetItemRectangle does not work for me
                            // we add a little extra space by using '_'
                            int itemWidth = (int)graphics.MeasureString(((String)_listBox.Items[i]) + "_", _listBox.Font).Width;
                            _listBox.Width = (_listBox.Width < itemWidth) ? itemWidth : _listBox.Width;
                        }
                    }
                }
                else
                {
                    ResetListBox();
                }
            }
            else
            {
                ResetListBox();
            }
        }

        private String GetWord()
        {
            String text = Text;
            int pos = SelectionStart;

            int posStart = text.LastIndexOf(' ', (pos < 1) ? 0 : pos - 1);
            posStart = (posStart == -1) ? 0 : posStart + 1;
            int posEnd = text.IndexOf(' ', pos);
            posEnd = (posEnd == -1) ? text.Length : posEnd;

            int length = ((posEnd - posStart) < 0) ? 0 : posEnd - posStart;

            return text.Substring(posStart, length);
        }

        private void InsertWord(String newTag)
        {
            String text = Text;
            int pos = SelectionStart;

            int posStart = text.LastIndexOf(' ', (pos < 1) ? 0 : pos - 1);
            posStart = (posStart == -1) ? 0 : posStart + 1;
            int posEnd = text.IndexOf(' ', pos);

            String firstPart = text.Substring(0, posStart) + newTag;
            String updatedText = firstPart + ((posEnd == -1) ? "" : text.Substring(posEnd, text.Length - posEnd));


            Text = updatedText;
            SelectionStart = firstPart.Length;
        }

        public String[] Values
        {
            get
            {
                return _values;
            }
            set
            {
                _values = value;
            }
        }

        public List<String> SelectedValues
        {
            get
            {
                String[] result = Text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                return new List<String>(result);
            }
        }

    }

}

Sample Usage

using System;
using System.Windows.Forms;

namespace AutoComplete
{
    public partial class TestForm : Form
    {
        private readonly String[] _values = { "one", "two", "three", "tree", "four", "fivee" };

        public TestForm()
        {
            InitializeComponent();
            // AutoComplete is our special textbox control on the form
            AutoComplete.Values = _values;
        }

    }
}

这篇关于的WinForms | C#|自动完成在一个文本框的中间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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