8

Our WinForms application does lazy loading of the data for auto complete of a textbox. The pseudocode for this is as follows;

  1. User types in TextBox
  2. On typing pause, determine if we need to fetch the auto complete data
  3. In worker thread, contact the server and fetch data
  4. Invoke back to the UI thread
  5. Set textBox.AutoCompleteCustomSource = fetchedAutoCompleteStringCollection;
  6. Force the textbox to drop down it's autocomplete dropdown.

I am currently having trouble with #6. As a hack, I do the following to simulate a keypress which works, but it does not work in all situations.

     // 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}" );

There must be a better way. I can't believe that I am the only person fetching auto complete data asynchronously. How should I be doing this?

EDIT: A Win32 call to cause the Auto Complete to dropdown would be acceptable. I don't mind PInvoking out if I have to.

4

2 に答える 2

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);
 ...
于 2011-12-01T15:56:24.850 に答える
2

通常、COM 相互運用機能を使用して、、、またはインターフェイスにアクセスIAutoCompleteIAutoComplete2ますIAutoCompleteDropDown。残念ながら、オートコンプリートを強制的にドロップダウンさせる方法はありません。

Spy++ を使用して、オート コンプリートが表示されたときにコントロールに送信されている Windows メッセージを確認することをお勧めします。それをアクティブにするコマンドメッセージが見つかるかもしれません。もちろん、これは実装の詳細ですが、ここに行く唯一の方法かもしれません。

于 2009-01-13T21:10:32.313 に答える