2010-10-14 16 views
0

J'utilise l'entrée d'un TextBox pour filtrer les informations affichées dans un ListBox. Je veux que le filtrage se produise chaque fois qu'une touche est pressée.C# Interrompre un événement Key en cours d'exécution à partir d'un TextBox lors de l'événement clé suivant

Le problème auquel je suis confronté est que si l'utilisateur tape un second caractère, un troisième, etc., le filtre se poursuivra pour chacune des touches. Par exemple. L'utilisateur tape 'a' et le filtrage commence, avant que le filtrage de la lettre 'a' ne soit terminé, l'utilisateur ajoute la lettre 'b' pour que la chaîne de recherche complète soit maintenant 'ab'.

À ce stade, je souhaite que le premier filtre s'arrête complètement et redémarre le nouveau filtre sur 'ab'.

private bool Interrupt = false; 
private bool Searching = true; 

private void tbxFilter_PreviewKeyDown(object sender, KeyEventArgs e) 
{ 
    if (Searching) 
    { 
     Interrupt = true; 
    } 
} 

private void tbxFilter_KeyUp(object sender, KeyEventArgs e) 
{ 
    Searching = true; 

    foreach (MyObject o in ListOfMyObjects) 
    { 
     if (Interrupt) 
     { 
      Interrupt = false; 
      break; 
     } 
     else 
     { 
      DoFilter(o); 
     } 
    } 

    Searching = false; 
} 

Le code ci-dessus montre à peu près ce que j'ai en ce moment avec quelques pièces spécifiques d'application supprimés (comme les types et les noms d'objets). Ce que je voudrais idéalement faire est de pouvoir faire une pause au début de la deuxième pression sur la touche (jusqu'à ce que Searching ait été défini sur false - indiquant que toutes les autres recherches sont terminées), mais en ajoutant une boucle while pour vérifier cela va juste bloquer le programme à ce moment-là.

Existe-t-il un moyen d'accomplir cela?

Merci

EDIT: Le contrôle qui affiche les éléments est un contrôle ListBox/ListView.

+0

Pourquoi ne pas utiliser la fonction de remplissage automatique de la zone de liste déroulante à la place? Il fait tout pour vous – w69rdy

+0

Le contrôle qui affiche les éléments est un contrôle ListBox ou ListView. Toutes mes excuses pour ne pas avoir précisé cela ci-dessus. – Andy

+0

Non c'est bon je l'ai eu, je me demandais juste s'il devait s'agir d'un ListBox ou si vous pouviez utiliser une combo à la place car il a une fonctionnalité très similaire à ce dont vous avez besoin pour vous éviter d'écrire du tout – w69rdy

Répondre

0

Je créerais un thread de travail pour le filtrage. Lorsqu'un nouveau processus de filtrage est lancé, le thread de travail en cours d'exécution est annulé (en définissant un indicateur ou un jeton d'annulation, voir .net 4.0 Task class).

Lorsque le thread est terminé, vous prenez le résultat et l'affichez en une seule action sur le thread graphique.

+0

L'utilisation d'une seule action pour mettre à jour l'interface est en fait la cause de l'implémentation de la recherche de cette manière. J'utilisais initialement un ICollectionView qui avait un délégué Filter pour fournir un filtrage intégré, le filtrage lui-même est assez rapide (mais pas aussi rapide que je le voudrais, mais peut-être acceptable) cependant, quand les changements sont rendus à la fin du processus, il y a un retard de plusieurs secondes pendant lequel l'interface utilisateur ne répond pas du tout car tous les chnages sont faits dans le thread UI. – Andy

+0

Dans Windows.Forms, vous pouvez utiliser pinvoke pour désactiver la mise à jour lors du paramétrage des données. Cela vous donnera une accélération majeure. Si vous utilisez WPF, il existe des moyens similaires (pas PinVoke, mais il existe des optimisations) pour définir les données en un seul appel. – testalino