开发者

Asynchronous autocomplete in winforms

开发者 https://www.devze.com 2022-12-17 17:53 出处:网络
Is there a way开发者_Go百科 to get asynchronous auto-complete in a Winforms TextBox or ComboBox?AJAX is so nice, and I would be amazed if the .NET framework doesn\'t have a thick client equivalent. Th

Is there a way开发者_Go百科 to get asynchronous auto-complete in a Winforms TextBox or ComboBox? AJAX is so nice, and I would be amazed if the .NET framework doesn't have a thick client equivalent.


There's no such feature out of the box, but it shouldn't be too hard to implement it yourself... Handle the TextChanged event, send a request asynchronously to get the matching items, and change the AutoCompleteSource when you get the result. You just need to be careful to access UI components on the UI thread, using the Invoke method (or you can use a BackgroundWorker and access the UI in the RunWorkerCompleted event)


I have written an async autocomplete class for a 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);
}

Sample implementation:

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;
        }
    }
}

How to use it:

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


I know that in MFC you can use SHAutoComplete and the shell will do it for you. However I'm not sure the best way to do this in WinForms, but it should be possible.

See this question and this one for some more info.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号