如何异步获取TextBox的AutoComplete数据?

时间:2009-01-13 18:56:15

标签: .net winforms autocomplete

我们的 WinForms 应用程序会延迟加载数据以自动完成文本框。伪代码如下:

  1. TextBox中的用户类型
  2. 在输入暂停时,确定是否需要获取自动完成数据
  3. 在工作线程中,与服务器联系并获取数据
  4. 调用回UI线程
  5. 设置textBox.AutoCompleteCustomSource = fetchedAutoCompleteStringCollection;
  6. 强制文本框下拉自动完成下拉列表。
  7. 我目前在#6遇到麻烦。作为一个黑客,我做以下操作来模拟一个有效的按键,但它并不适用于所有情况。

         // This is a hack, but the only way that I have found to get the autocomplete
         // to drop down once the data is returned.
         textBox.SelectionStart = textBox.Text.Length;
         textBox.SelectionLength = 0;
         SendKeys.Send( " {BACKSPACE}" );
    

    必须有更好的方法。我无法相信我是唯一一个异步获取自动完成数据的人。我该怎么做?

    编辑:可以接受导致“自动完成”下拉列表的Win32调用。如果必须的话,我不介意PInvoking。

2 个答案:

答案 0 :(得分:5)

我只使用托管代码为TextBox编写了一个异步自动完成类。希望它有所帮助。

using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;

namespace TextboxAutocomplete
{
    public abstract class AutoCompleteSource
    {
        private TextBox mTextBox;
        private AutoCompleteMode mAutoCompleteMode;

        public AutoCompleteSource(TextBox textbox) :
            this(textbox, AutoCompleteMode.Suggest) { }

        public AutoCompleteSource(TextBox textbox, AutoCompleteMode mode)
        {
            if (textbox == null)
                throw new ArgumentNullException("textbox");

            if (textbox.IsDisposed)
                throw new ArgumentException("textbox");

            mTextBox = textbox;
            mAutoCompleteMode = mode;

            mTextBox.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.None;

            BackgroundWorker autoCompleteLoader = new BackgroundWorker();
            autoCompleteLoader.DoWork += new DoWorkEventHandler(autoCompleteLoader_DoWork);
            autoCompleteLoader.RunWorkerCompleted += new RunWorkerCompletedEventHandler(autoCompleteLoader_RunWorkerCompleted);
            autoCompleteLoader.RunWorkerAsync();
        }

        void autoCompleteLoader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            AutoCompleteStringCollection collection = e.Result as AutoCompleteStringCollection;
            if (collection == null) return;

            if (mTextBox.InvokeRequired)
            {
                mTextBox.Invoke(new SetAutocompleteSource(DoSetAutoCompleteSource), new object[] { collection });
            }
            else
            {
                DoSetAutoCompleteSource(collection);
            }
        }

        protected void DoSetAutoCompleteSource(AutoCompleteStringCollection collection)
        {
            if (mTextBox.IsDisposed) return;

            mTextBox.AutoCompleteMode = mAutoCompleteMode;
            mTextBox.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.CustomSource;
            mTextBox.AutoCompleteCustomSource = collection;
        }

        void autoCompleteLoader_DoWork(object sender, DoWorkEventArgs e)
        {
            List<string> autoCompleteItems = GetAutocompleteItems();
            if (autoCompleteItems == null) return;
            AutoCompleteStringCollection collection = new AutoCompleteStringCollection();
            collection.AddRange(GetAutocompleteItems().ToArray());
            e.Result = collection;
        }

        protected abstract List<string> GetAutocompleteItems();
    }

    internal delegate void SetAutocompleteSource(AutoCompleteStringCollection collection);
}

示例实施:

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

namespace TextboxAutocomplete
{
    class MockAutoCompleteSource : AutoCompleteSource
    {
        public MockAutoCompleteSource(TextBox textbox)
            : base(textbox)
        {

        }

        protected override List<string> GetAutocompleteItems()
        {
            List<string> result = new List<string>();
            for (int i = 0; i < 2500; i++)
            {
                result.Add(Guid.NewGuid().ToString());
            }

            return result;
        }
    }
}

如何使用它:

 ...
 TextBox myTextbox = new TextBox();
 MockAutoCompleteSource autoComplete =
      new MockAutoCompleteSource(myTextbox);
 ...

答案 1 :(得分:2)

通常,您将使用COM互操作并访问IAutoCompleteIAutoComplete2IAutoCompleteDropDown界面。不幸的是,其中没有一种方法可以强制自动完成功能下降。

您可能希望使用Spy ++并查看自动完成显示时发送给控件的Windows消息。您可能会找到一条命令消息来激活它。当然,这是一个实现细节,但它可能是唯一的方法。