2010-09-23 14 views
8

Estoy usando la vista de árbol de WPF por primera vez y estoy asombrado de todas las cosas básicas que hace no do. Una de ellas es la navegación por teclado, implementada en cualquier vista de árbol que se precie, p. en Windows Explorer o Regedit.Vista de árbol WPF: ¿cómo implementar la navegación por teclado como en Explorer?

Esta es la forma en que debería funcionar:

Si la vista de árbol tiene el foco y el tipo (letras/números) la selección debe pasar al primer elemento visible (también conocido como ampliado) por debajo del elemento seleccionado en ese momento que coincide con la cadena que escribí y la traigo a la vista. Si no se encuentra coincidencia debajo del elemento actual, la búsqueda debe continuar desde la parte superior. Si no se encuentra una coincidencia, el elemento seleccionado no debe cambiar.

Mientras sigo escribiendo, la cadena de búsqueda crece y se refina la búsqueda. Si dejo de escribir durante un tiempo determinado (2-5 segundos), la cadena de búsqueda se vacía.

Estoy preparado para programar esto "a mano" desde cero, pero como esto es muy básico, pensé que seguramente alguien ya había hecho exactamente esto.

Respuesta

4

Es curioso, este no parece ser un tema popular. De todos modos, mientras tanto, he desarrollado una solución al problema que me satisface:

Adjunto un comportamiento a los elementos TreeView. En ese comportamiento, manejo eventos de KeyUp. En el controlador de eventos KeyUp, busco el árbol visual de arriba a abajo a medida que se muestra. Si encuentro un primer nodo coincidente (cuyo nombre comienza con la letra de la tecla presionada) selecciono ese nodo.

+4

¿Podría adjuntar un código de muestra? Gracias. –

+0

También agradecería un código de muestra –

+0

@Helge Klein: Como usted dijo, ya ha desarrollado una solución, ¿podría compartir el código de muestra? – digitguy

1

Yo también estaba buscando la navegación con el teclado, increíble cómo la solución era obvia para los elementos modelados.

Establecer SelectedValuePath en ListView o TreeView proporciona este comportamiento. Si los elementos son plantillas, la configuración de la propiedad adjunta: TextSearch.TextPath a la ruta de la propiedad para buscar también hará el truco.

Espero que esto ayude, definitivamente funcionó para mí.

+0

No puedo hacer que esto funcione. ¿Podría proporcionar un ejemplo de código para el caso en que TreeView utiliza una HierarchicalDataTemplate? –

0

No es muy sencillo como esperamos que sea. Pero la mejor solución que he encontrado está aquí: http://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode

Avíseme si necesita más detalles.

+0

Conozco ese artículo, por supuesto. No describe cómo implementar la navegación por teclado. –

+0

Sí, estoy de acuerdo. Aunque podemos implementar una búsqueda simple usando los métodos en ese artículo, es muy difícil hacer una búsqueda incremental. Como dijiste, ya has desarrollado una solución, ¿podrías compartir el código de muestra? – digitguy

1

Sé que es un tema antiguo, pero creo que sigue siendo relevante para algunas personas. Hice esta solución. Se adjunta al KeyUp y al evento TextInput en un WPF TreeView. Estoy usando TextInput además de KeyUp ya que tuve dificultades para traducir caracteres "nacionales" a caracteres reales con KeyEventArgs. Eso fue mucho más sencillo con TextInput.

// <TreeView Name="treeView1" KeyUp="treeView1_KeyUp" TextInput="treeView1_TextInput"/> 

    private bool searchdeep = true;    // Searches in subitems 
    private bool searchstartfound = false;  // true when current selected item is found. Ensures that you don't seach backwards and that you only search on the current level (if not searchdeep is true) 
    private string searchterm = "";    // what to search for 
    private DateTime LastSearch = DateTime.Now; // resets searchterm if last input is older than 1 second. 

    private void treeView1_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) 
    { 
     // reset searchterm if any "special" key is pressed 
     if (e.Key < Key.A) 
      searchterm = ""; 

    } 

    private void treeView1_TextInput(object sender, TextCompositionEventArgs e) 
    { 
     if ((DateTime.Now - LastSearch).Seconds > 1) 
      searchterm = ""; 

     LastSearch = DateTime.Now; 
     searchterm += e.Text; 
     searchstartfound = treeView1.SelectedItem == null; 

     foreach (var t in treeView1.Items) 
      if (SearchTreeView((TreeViewItem) t, searchterm.ToLower())) 
       break; 
    } 

    private bool SearchTreeView(TreeViewItem node, string searchterm) 
    { 
     if (node.IsSelected) 
      searchstartfound = true; 

     // Search current level first 
     foreach (TreeViewItem subnode in node.Items) 
     { 
      // Search subnodes to the current node first 
      if (subnode.IsSelected) 
      { 
       searchstartfound = true; 
       if (subnode.IsExpanded) 
        foreach (TreeViewItem subsubnode in subnode.Items) 
         if (searchstartfound && subsubnode.Header.ToString().ToLower().StartsWith(searchterm)) 
         { 
          subsubnode.IsSelected = true; 
          subsubnode.IsExpanded = true; 
          subsubnode.BringIntoView(); 
          return true; 
         } 
      } 
      // Then search nodes on the same level 
      if (searchstartfound && subnode.Header.ToString().ToLower().StartsWith(searchterm)) 
      { 
       subnode.IsSelected = true; 
       subnode.BringIntoView(); 
       return true; 
      } 
     } 

     // If not found, search subnodes 
     foreach (TreeViewItem subnode in node.Items) 
     { 
      if (!searchstartfound || searchdeep) 
       if (SearchTreeView(subnode, searchterm)) 
       { 
        node.IsExpanded = true; 
        return true; 
       } 
     } 

     return false; 
    } 
+0

¡Gracias! Esto funciona maravillosamente.Solo tuve que cambiar el tiempo a 500 milisegundos para lograr lo que necesito. – JMooney

Cuestiones relacionadas