2010-11-17 3 views
3

J'ai un contrôle WPF Listbox et je voudrais permettre à l'utilisateur de changer l'élément sélectionné en utilisant la frappe anticipée. Le comportement que je cherche est exactement comme Windows Explorer. Pendant que vous continuez à taper le texte d'un nom de dossier, la liste continuera à sélectionner l'élément le plus correct.Sélectionnez les éléments dans WPF Listbox via le clavier "Type-Ahead" recherche

Par exemple assumer cette structure de dossiers:

OtherFolderName 
MyFirstFolder 
MyFirstFileFolder 
MyFirstList 

Si vous sélectionnez OtherFolderName avec la souris, puis commencez à taper MyFirstF l'élément MyFirstFolder sera sélectionné, mais si vous continuez à taper MyFirstFi l'élément MyFirstFileFolder sera sélectionné.

Mon Listbox WPF ne présente pas ce comportement, j'espère pouvoir l'activer facilement, comme l'ancienne boîte de liste WinForms l'a fait.

Répondre

6

Jetez un oeil à la classe TextSearch, en particulier la propriété TextSearch.TextPath ci-joint:

<ListBox TextSearch.TextPath="FolderName" ... /> 

La propriété TextSearch.TextPath permet la recherche de texte et indique comment extraire le texte de recherche de chaque élément. Dans ce cas, j'ai supposé que chacun de vos objets Dossier a une propriété nommée "FolderName".

Si cela ne vous convient pas, vous devrez probablement implémenter votre propre recherche, car la fonction TextSearch n'est pas particulièrement modifiable. Pour ce faire:

  1. gérer l'événement TextInput
  2. Comparez le temps de la TextInput actuelle avec le TextInput avant. Si assez proche ensemble, ajoutez à la chaîne de préfixe sinon placez-le au caractère unique tapé.
  3. Rechercher tous les éléments pour le préfixe donné & si trouvé set SelectedItem.

Je construirais ceci en tant que classe séparée en utilisant une propriété jointe, similaire à la classe TextSearch intégrée.

+1

qui est exactement ce que je cherchais. Merci. – Nate

0

J'utilise une TextBox cachée qui apparaît brièvement pendant que la personne est en train de taper, et se réinitialise après quelques secondes et efface, de sorte qu'elle n'essaie pas de faire correspondre son contenu après l'expiration du délai. La personne taperait dans le ListBox et son événement KeyUp remplira le TextBox en raison de la liaison sur SearchText. Lorsque SearchText est rempli, il déclenche MyFilteredItems() pour effectuer une correspondance entre ce texte et le contrôle ListBox. Ensuite, si la personne appuie sur Entrée, la sélection irait dans un autre TextBox (non répertorié dans le code XAML, mais est fourni comme mis en commentaire dans le code) et être supprimé de lstPickList. Le TextBox est ensuite effacé et la minuterie réinitialise.

XAML:

<TextBox Name="txtPicker" IsReadOnly="True" Foreground="LightGreen" FontFamily="Consolas" Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"></TextBox> 

<ListBox Name="lstPickList" Grid.Row="1" ItemsSource="{Binding MyFilteredItems}" KeyUp="lstPickList_KeyUp"></ListBox> 

Et c'est le correspondant code-behind:

public partial class MainWindow : Window, INotifyPropertyChanged 
{ 
    private Timer t = new Timer();  
    public System.Windows.Threading.DispatcherTimer tCleanup = 
     new System.Windows.Threading.DispatcherTimer(); 

    private string _searchText; 
    public string SearchText 
    { 
     get { return _searchText; } 
     set 
     { 
      _searchText = value; 

      OnPropertyChanged("SearchText"); 
      OnPropertyChanged("MyFilteredItems"); 
     } 
    } 

    public List<string> MyItems { get; set; }   

    public IEnumerable<string> MyFilteredItems 
    { 
     get 
     { 
      if (SearchText == null) return MyItems; 

      return MyItems.Where(x => x.ToUpper().StartsWith(SearchText.ToUpper())); 
     }    
    } 


    public MainWindow() 
    { 
     InitializeComponent(); 

     MyItems = new List<string>() { "ABC", "DEF", "GHI" };      
     this.DataContext = this; 

     t.Interval = 1000; 
     t.Elapsed += new ElapsedEventHandler(timerCounter); 
     tCleanup.Interval = new TimeSpan(0,0,1); 
     tCleanup.Tick += new EventHandler(cleanupCounter_Tick);   
     txtPicker.Visibility = Visibility.Collapsed; 
     tCleanup.Start(); 
    } 
    private static int counter = 0; 
    protected void timerCounter(object sender, ElaspedEventArgs e) 
    { 
     counter++; 
    } 

    protected void cleanupCounter_Tick(object sender, EventArgs e) 
    { 
     if (counter > 2 && txtPicker.Visibility == Visibility.Visible) 
      txtPicker.Visibility = Visibility.Collapsed; 
    } 

    private void lstPickList_KeyUp(object sender, KeyEventArgs e) 
    { 
     ListBox lst = (ListBox)sender; 
     string strg = Convert.ToString(e.Key.ToString().Replace("D","")); 
     if (counter < 2) 
     { 
      txtPicker.Visibility = Visibility.Visible; 
      t.Start(); 
      if (strg == "Return") 
      { 
       txtPicker.Text += "{Enter}"; 
       SearchText += "{Enter}"; 
      } 
      else 
      { 
       txtPicker.Text += strg; 
       SearchText += strg; 
      } 
     } 
     else 
     { 
      SearchText = strg; 
      txtPicker.Text = strg; 
      t.Stop(); 
      counter = 0; 
      t.Start(); 
     } 

     if (strg == "Return") 
     { 
      // This next line would be if you had a "selected items" ListBox to store the item 
      // lstSelectedList.Items.Add(lstPickList.SelectedItem); 
      lstPickList.Items.Remove(lstPickList.SelectedItem); 
      t.Stop(); 
      txtPicker.Visibility = Visibility.Collapsed; 
      counter = 0; 
      txtPicker.Text = String.Empty; 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    void OnPropertyChanged(string name) 
    { 
     if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(name)); 
    } 
} 
Questions connexes