Seleccionar elementos de WPF cuadro de lista a través del teclado de búsqueda “de escritura anticipada”

StackOverflow https://stackoverflow.com/questions/4209774

Pregunta

Tengo un cuadro de lista de control de WPF y me gustaría para permitir al usuario cambiar el elemento seleccionado mediante el uso de escritura anticipada. El comportamiento que estoy buscando es exactamente igual que el Explorador de Windows. A medida que continúe a escribir el texto de un nombre de carpeta, la lista se mantenga seleccionado el elemento más correcto.

Por ejemplo asumir esta estructura de carpetas:

OtherFolderName
MyFirstFolder
MyFirstFileFolder
MyFirstList

Si selecciona OtherFolderName con el ratón, a continuación, empezar a escribir MyFirstF se seleccionará el MyFirstFolder artículo, pero si continúa escribiendo MyFirstFi se seleccionará el MyFirstFileFolder artículo.

Mi WPF cuadro de lista no presenta este behavor, espero que pueda fácilmente activarlo, como el cuadro de lista WinForms viejos hizo exactamente esto.

¿Fue útil?

Solución

Tome un vistazo a la clase TextSearch, específicamente la propiedad TextSearch.TextPath adjunto:

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

La propiedad TextSearch.TextPath permite la búsqueda de texto y especifica cómo extraer el texto de búsqueda de cada elemento. En este caso asumí cada uno de sus objetos de carpeta tiene una propiedad denominada "FolderName".

Si esto no hace todo lo que está buscando, es probable que tenga que poner en práctica su propia búsqueda, ya que la función TextSearch no es particularmente modificables. Para hacer esto:

  1. Controle el evento TextInput
  2. Compare el tiempo de la TextInput TextInput actual con el anterior. Si lo suficientemente cerca, anexados para prefijo de cadena establece lo contrario al carácter único escrito.
  3. Buscar todos los artículos para el prefijo dado y si SelectedItem conjunto encontrado.

Yo construiría esto como una clase separada usando una propiedad asociada, similar a la clase incorporada TextSearch.

Otros consejos

I utilizar un cuadro de texto oculto que aparece brevemente mientras la persona está escribiendo, y se restablece después de un par de segundos y desaparece, por lo que no utilizar la concordancia en su contenido después de que el temporizador expira. La persona tendría que escribir en el cuadro de lista, y su caso KeyUp va a llenar en el cuadro de texto debido a la unión de SearchText. Cuando se llena SearchText, se dispara MyFilteredItems() para realizar una correspondencia entre el texto y el cuadro de lista. Entonces, si las prensas de persona a entrar, la selección iría en otro cuadro de texto (que no figura en el XAML, pero se proporciona como se ha comentado en el código) y ser limpiado de lstPickList. El cuadro de texto se borra y luego se reinicia el temporizador.

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>

Y entonces este es el correspondiente código subyacente:

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));
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top