2009-01-13 8 views
8

Nos WinForms application effectue le chargement paresseux des données pour auto complète d'une zone de texte. Le pseudocode pour ceci est comme suit;Comment chercher des données de manière asynchrone pour une saisie semi-automatique TextBox?

  1. types d'utilisateurs dans TextBox
  2. sur la saisie pause, déterminer si nous devons chercher les données complètes auto
  3. Dans thread de travail, contacter le serveur et récupérer les données
  4. Invoke au thread de l'interface utilisateur
  5. Set textBox.AutoCompleteCustomSource = fetchedAutoCompleteStringCollection;
  6. Forcer la zone de texte à dérouler c'est déroulant autocomplete.

Je suis actuellement des problèmes aveC# 6. En tant que hack, je fais ce qui suit pour simuler une pression de touche qui fonctionne, mais il ne fonctionne pas dans toutes les 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}"); 

Il doit y avoir un meilleur moyen. Je ne peux pas croire que je suis la seule personne à aller chercher des données auto complètes de manière asynchrone. Comment devrais-je faire ça?

EDIT: Un appel Win32 pour provoquer la liste déroulante Auto Complete est acceptable. Ça ne me dérange pas de m'envoyer en l'air si je le dois.

Répondre

5

J'ai écrit une classe de saisie semi-automatique pour async une zone de texte en utilisant le code seulement réussi. J'espère que cela aide.

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

exemple d'implémentation:

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

Comment l'utiliser:

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

Je n'ai pas essayé votre code, mais il semble bon, donc je vais l'accepter comme répondre. Merci. –

2

Généralement, vous utiliseriez COM interop et accéderiez à IAutoComplete, IAutoComplete2 ou à l'interface IAutoCompleteDropDown. Malheureusement, aucun d'entre eux n'a de méthodes pour forcer l'autocomplétion à tomber.

Vous pouvez utiliser Spy ++ et regarder les messages Windows qui sont envoyés au contrôle à l'affichage de l'affichage automatique. Vous pourriez trouver un message de commande qui l'activera. Bien sûr, cela est un détail de mise en œuvre, mais il pourrait être le seul moyen d'y aller.

Questions connexes