代码之家  ›  专栏  ›  技术社区  ›  corymathews

C~*自动完成

  •  43
  • corymathews  · 技术社区  · 15 年前

    我正在尝试向文本框添加自动完成功能,结果来自数据库。它们的格式是

    [001]最后,第一中间

    当前必须键入[001]…获取要显示的条目。 所以问题是,即使我先输入名字,我也希望它完成 . 所以如果一个条目是

    [001]史密斯,约翰·D

    如果我开始输入john,那么这个条目应该显示在自动完成的结果中。

    当前代码看起来像

    AutoCompleteStringCollection acsc = new AutoCompleteStringCollection();
    txtBox1.AutoCompleteCustomSource = acsc;
    txtBox1.AutoCompleteMode = AutoCompleteMode.Suggest; 
    txtBox1.AutoCompleteSource = AutoCompleteSource.CustomSource; 
    
    ....
    
    if (results.Rows.Count > 0)
        for (int i = 0; i < results.Rows.Count && i < 10; i++) 
        {
            row = results.Rows[i];
            acsc.Add(row["Details"].ToString());
        }
    }
    

    结果是包含查询结果的数据集

    查询是使用LIKE语句的简单搜索查询。如果不使用自动完成功能,只将结果放入数组中,则返回正确的结果。

    有什么建议吗?

    编辑:

    这是返回结果的查询

    SELECT Name from view_customers where Details LIKE '{0}'
    

    其中0是搜索字符串的占位符。

    6 回复  |  直到 7 年前
        1
  •  46
  •   Steven Richards    15 年前

    现有的自动完成功能只支持按前缀搜索。似乎没有任何体面的方法来推翻这种行为。

    有些人通过重写 OnTextChanged 事件。这可能是你最好的选择。

    例如,可以添加 ListBox 就在下面 TextBox 并将其默认可见性设置为false。然后你可以使用 文本更改 事件 文本框 以及 SelectedIndexChanged 事件 列表框 显示和选择项目。

    这似乎是一个很好的基本例子:

    public Form1()
    {
        InitializeComponent();
    
    
        acsc = new AutoCompleteStringCollection();
        textBox1.AutoCompleteCustomSource = acsc;
        textBox1.AutoCompleteMode = AutoCompleteMode.None;
        textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
        acsc.Add("[001] some kind of item");
        acsc.Add("[002] some other item");
        acsc.Add("[003] an orange");
        acsc.Add("[004] i like pickles");
    }
    
    void textBox1_TextChanged(object sender, System.EventArgs e)
    {
        listBox1.Items.Clear();
        if (textBox1.Text.Length == 0)
        {
        hideResults();
        return;
        }
    
        foreach (String s in textBox1.AutoCompleteCustomSource)
        {
        if (s.Contains(textBox1.Text))
        {
            Console.WriteLine("Found text in: " + s);
            listBox1.Items.Add(s);
            listBox1.Visible = true;
        }
        }
    }
    
    void listBox1_SelectedIndexChanged(object sender, System.EventArgs e)
    {
        textBox1.Text = listBox1.Items[listBox1.SelectedIndex].ToString();
        hideResults();
    }
    
    void listBox1_LostFocus(object sender, System.EventArgs e)
    {
        hideResults();
    }
    
    void hideResults()
    {
        listBox1.Visible = false;
    }
    

    不用太费劲,您可以做很多事情:将文本附加到文本框中,捕获其他键盘命令,等等。

        2
  •  5
  •   Jim Scott    15 年前

    如果决定使用基于用户输入的查询,请确保使用sqlparameters避免SQL注入攻击

    SqlCommand sqlCommand = new SqlCommand();
    sqlCommand.CommandText = "SELECT Name from view_customers where Details LIKE '%" + @SearchParam + "%'";
    sqlCommand.Parameters.AddWithValue("@SearchParam", searchParam);
    
        3
  •  4
  •   noelicus    10 年前

    下面是一个继承 ComboBox 控件类,而不是用新控件替换整个组合框。当您在文本框中键入内容时,它会显示自己的下拉列表,但单击以显示下拉列表会像以前一样处理(即,不使用此代码)。因此,您可以获得适当的本地控制和外观。

    如果您想改进,请使用它,修改它并编辑答案!

    class ComboListMatcher : ComboBox, IMessageFilter
    {
        private Control ComboParentForm; // Or use type "Form" 
        private ListBox listBoxChild;
        private int IgnoreTextChange;
        private bool MsgFilterActive = false;
    
        public ComboListMatcher()
        {
            // Set up all the events we need to handle
            TextChanged += ComboListMatcher_TextChanged;
            SelectionChangeCommitted += ComboListMatcher_SelectionChangeCommitted;
            LostFocus += ComboListMatcher_LostFocus;
            MouseDown += ComboListMatcher_MouseDown;
            HandleDestroyed += ComboListMatcher_HandleDestroyed;
        }
    
        void ComboListMatcher_HandleDestroyed(object sender, EventArgs e)
        {
            if (MsgFilterActive)
                Application.RemoveMessageFilter(this);
        }
    
        ~ComboListMatcher()
        {
        }
    
        private void ComboListMatcher_MouseDown(object sender, MouseEventArgs e)
        {
            HideTheList();
        }
    
        void ComboListMatcher_LostFocus(object sender, EventArgs e)
        {
            if (listBoxChild != null && !listBoxChild.Focused)
                HideTheList();
        }
    
        void ComboListMatcher_SelectionChangeCommitted(object sender, EventArgs e)
        {
            IgnoreTextChange++;
        }
    
        void InitListControl()
        {
            if (listBoxChild == null)
            {
                // Find parent - or keep going up until you find the parent form
                ComboParentForm = this.Parent;
    
                if (ComboParentForm != null)
                {
                    // Setup a messaage filter so we can listen to the keyboard
                    if (!MsgFilterActive)
                    {
                        Application.AddMessageFilter(this);
                        MsgFilterActive = true;
                    }
    
                    listBoxChild = listBoxChild = new ListBox();
                    listBoxChild.Visible = false;
                    listBoxChild.Click += listBox1_Click;
                    ComboParentForm.Controls.Add(listBoxChild);
                    ComboParentForm.Controls.SetChildIndex(listBoxChild, 0); // Put it at the front
                }
            }
        }
    
    
        void ComboListMatcher_TextChanged(object sender, EventArgs e)
        {
            if (IgnoreTextChange > 0)
            {
                IgnoreTextChange = 0;
                return;
            }
    
            InitListControl();
    
            if (listBoxChild == null)
                return;
    
            string SearchText = this.Text;
    
            listBoxChild.Items.Clear();
    
            // Don't show the list when nothing has been typed
            if (!string.IsNullOrEmpty(SearchText))
            {
                foreach (string Item in this.Items)
                {
                    if (Item != null && Item.Contains(SearchText, StringComparison.CurrentCultureIgnoreCase))
                        listBoxChild.Items.Add(Item);
                }
            }
    
            if (listBoxChild.Items.Count > 0)
            {
                Point PutItHere = new Point(this.Left, this.Bottom);
                Control TheControlToMove = this;
    
                PutItHere = this.Parent.PointToScreen(PutItHere);
    
                TheControlToMove = listBoxChild;
                PutItHere = ComboParentForm.PointToClient(PutItHere);
    
                TheControlToMove.Show();
                TheControlToMove.Left = PutItHere.X;
                TheControlToMove.Top = PutItHere.Y;
                TheControlToMove.Width = this.Width;
    
                int TotalItemHeight = listBoxChild.ItemHeight * (listBoxChild.Items.Count + 1);
                TheControlToMove.Height = Math.Min(ComboParentForm.ClientSize.Height - TheControlToMove.Top, TotalItemHeight);
            }
            else
                HideTheList();
        }
    
        /// <summary>
        /// Copy the selection from the list-box into the combo box
        /// </summary>
        private void CopySelection()
        {
            if (listBoxChild.SelectedItem != null)
            {
                this.SelectedItem = listBoxChild.SelectedItem;
                HideTheList();
                this.SelectAll();
            }
        }
    
        private void listBox1_Click(object sender, EventArgs e)
        {
            var ThisList = sender as ListBox;
    
            if (ThisList != null)
            {
                // Copy selection to the combo box
                CopySelection();
            }
        }
    
        private void HideTheList()
        {
            if (listBoxChild != null)
                listBoxChild.Hide();
        }
    
        public bool PreFilterMessage(ref Message m)
        {
            if (m.Msg == 0x201) // Mouse click: WM_LBUTTONDOWN
            {
                var Pos = new Point((int)(m.LParam.ToInt32() & 0xFFFF), (int)(m.LParam.ToInt32() >> 16));
    
                var Ctrl = Control.FromHandle(m.HWnd);
                if (Ctrl != null)
                {
                    // Convert the point into our parent control's coordinates ...
                    Pos = ComboParentForm.PointToClient(Ctrl.PointToScreen(Pos));
    
                    // ... because we need to hide the list if user clicks on something other than the list-box
                    if (ComboParentForm != null)
                    {
                        if (listBoxChild != null &&
                            (Pos.X < listBoxChild.Left || Pos.X > listBoxChild.Right || Pos.Y < listBoxChild.Top || Pos.Y > listBoxChild.Bottom))
                        {
                            this.HideTheList();
                        }
                    }
                }
            }
            else if (m.Msg == 0x100) // WM_KEYDOWN
            {
                if (listBoxChild != null && listBoxChild.Visible)
                {
                    switch (m.WParam.ToInt32())
                    {
                        case 0x1B: // Escape key
                            this.HideTheList();
                            return true;
    
                        case 0x26: // up key
                        case 0x28: // right key
                            // Change selection
                            int NewIx = listBoxChild.SelectedIndex + ((m.WParam.ToInt32() == 0x26) ? -1 : 1);
    
                            // Keep the index valid!
                            if (NewIx >= 0 && NewIx < listBoxChild.Items.Count)
                                listBoxChild.SelectedIndex = NewIx;
                            return true;
    
                        case 0x0D: // return (use the currently selected item)
                            CopySelection();
                            return true;
                    }
                }
            }
    
            return false;
        }
    }
    
        4
  •  0
  •   Damovisa    15 年前

    如果您正在运行该查询(使用 {0} 被输入的字符串替换),您可能需要:

    SELECT Name from view_customers where Details LIKE '%{0}%'
    

    LIKE 仍然需要 % 性格…是的,您应该使用参数而不是信任用户的输入:)

    此外,您似乎还返回了 Name 列,但查询 Details 列。如果有人输入“john smith”,如果不在 细节 列你将得不到你想要的。

        5
  •  0
  •   mike jwezorek    7 年前

    这将为您提供所需的自动完成行为。

    附加的示例是一个完整的工作表单,只需要您的数据源和绑定的列名。

    using System;
    using System.Data;
    using System.Windows.Forms;
    
    public partial class frmTestAutocomplete : Form
    {
    
        private DataTable maoCompleteList;
        private const string MC_DISPLAY_COL = "name";
        private const string MC_ID_COL = "id";
    
        public frmTestAutocomplete()
        {
            InitializeComponent();
        }
    
        private void frmTestAutocomplete_Load(object sender, EventArgs e)
        {
            using (clsDataAccess oData = new clsDataAccess())
            {
    
                maoCompleteList = oData.PurificationRuns;
                maoCompleteList.CaseSensitive = false; //turn off case sensitivity for searching
    
                testCombo.DisplayMember = MC_DISPLAY_COL;
                testCombo.ValueMember = MC_ID_COL; 
                testCombo.DataSource = GetDataTableFromDatabase();
                testCombo.SelectedIndexChanged += testCombo_SelectedIndexChanged;
                testCombo.KeyUp += testCombo_KeyUp; 
            }
        }
    
    
        private void testCombo_KeyUp(object sender, KeyEventArgs e)
        {
            //use keyUp event, as text changed traps too many other evengts.
    
            ComboBox oBox = (ComboBox)sender;
            string sBoxText = oBox.Text;
    
            DataRow[] oFilteredRows = maoCompleteList.Select(MC_DISPLAY_COL + " Like '%" + sBoxText + "%'");
    
            DataTable oFilteredDT = oFilteredRows.Length > 0
                                    ? oFilteredRows.CopyToDataTable()
                                    : maoCompleteList;
    
            //NOW THAT WE HAVE OUR FILTERED LIST, WE NEED TO RE-BIND IT WIHOUT CHANGING THE TEXT IN THE ComboBox.
    
            //1).UNREGISTER THE SELECTED EVENT BEFORE RE-BINDING, b/c IT TRIGGERS ON BIND.
            testCombo.SelectedIndexChanged -= testCombo_SelectedIndexChanged; //don't select on typing.
            oBox.DataSource = oFilteredDT; //2).rebind to filtered list.
            testCombo.SelectedIndexChanged += testCombo_SelectedIndexChanged;
    
    
            //3).show the user the new filtered list.
            oBox.DroppedDown = true; //do this before repainting the text, as it changes the dropdown text.
    
            //4).binding data source erases text, so now we need to put the user's text back,
            oBox.Text = sBoxText;
            oBox.SelectionStart = sBoxText.Length; //5). need to put the user's cursor back where it was.
    
    
        }
    
        private void testCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
    
            ComboBox oBox = (ComboBox)sender;
    
            if (oBox.SelectedValue != null)
            {
                MessageBox.Show(string.Format(@"Item #{0} was selected.", oBox.SelectedValue));
            }
        }
    }
    
    //=====================================================================================================
    //      code from frmTestAutocomplete.Designer.cs
    //=====================================================================================================
    partial class frmTestAutocomplete
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
    
        #region Windows Form Designer generated code
    
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.testCombo = new System.Windows.Forms.ComboBox();
            this.SuspendLayout();
            // 
            // testCombo
            // 
            this.testCombo.FormattingEnabled = true;
            this.testCombo.Location = new System.Drawing.Point(27, 51);
            this.testCombo.Name = "testCombo";
            this.testCombo.Size = new System.Drawing.Size(224, 21);
            this.testCombo.TabIndex = 0;
            // 
            // frmTestAutocomplete
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(292, 273);
            this.Controls.Add(this.testCombo);
            this.Name = "frmTestAutocomplete";
            this.Text = "frmTestAutocomplete";
            this.Load += new System.EventHandler(this.frmTestAutocomplete_Load);
            this.ResumeLayout(false);
    
        }
    
        #endregion
    
        private System.Windows.Forms.ComboBox testCombo;
    }
    
        6
  •  -1
  •   Sherif Hamdy    8 年前

    有两种方法在使用SQL的自动完成文本框控件中成功:

    但您应该做以下操作:

    A-创建新项目

    B-将组件类添加到项目并删除component1.designer“根据您给组件类的名称”

    C下载 "Download sample - 144.82 KB" 然后打开它并从autocompletetextbox.cs打开autocompletetextbox类。
    d-选择图像中所示的全部,并将其复制到当前组件类

    http://i.stack.imgur.com/oSqCa.png

    e-最终-运行项目并停止以在工具箱中查看新的自动完成文本框。

    现在您可以添加以下两个方法,您可以将SQL与它们一起使用

    1英寸负荷

    private void Form1_Load(object sender, EventArgs e)
      {            
       SqlConnection cn = new SqlConnection(@"server=.;database=My_dataBase;integrated security=true");
       SqlDataAdapter da = new SqlDataAdapter(@"SELECT [MyColumn] FROM [my_table]", cn);
       DataTable dt = new DataTable();
       da.Fill(dt);
    
       List<string> myList = new List<string>();
        foreach (DataRow row in dt.Rows)
           {
              myList.Add((string)row[0]);
           }
    
       autoCompleteTextbox1.AutoCompleteList = myList;
        }  
    

    2-在TextChanged事件中

     private void autoCompleteTextbox_TextChanged(object sender, EventArgs e)
            {           
             SqlConnection cn = new SqlConnection(@"server=.;database=My_dataBase;integrated security=true");
             SqlDataAdapter da = new SqlDataAdapter(@"SELECT [MyColumn] FROM [my_table]", cn);
             DataTable dt = new DataTable();
             da.Fill(dt);
    
         List<string> myList = new List<string>();
          foreach (DataRow row in dt.Rows)
            {
              myList.Add((string)row[0]);
            }
    
       autoCompleteTextbox2.AutoCompleteList = myList;
    
        }