el Guille, la Web del Visual Basic, C#, .NET y más...

gsBuscarTexto

Utilidad para buscar ficheros y opcionalmente para buscar y reemplazar textos en esos ficheros

 
Publicado el 09/Dic/2007
Actualizado el 11/Feb/2008
Autor: Guillermo 'guille' Som

Nueva revisión (mejorada) del 10/Feb/2008: gsBuscarTexto v2.0.6.0

11/Feb: Actualizado el ZIP con el ejecutable v2.0.6.7


Nueva versión para Visual Basic 2008 de la utilidad de buscar ficheros en los directorios (y subdirectorios) indicados, que utiliza controles de WPF en una aplicación de Windows.Forms, que cuando esté más terminada, opcionalmente también buscará y reemplazará textos en esos ficheros.



 

Introducción:

Esta utilidad (al menos a la hora de escribir estas líneas el 9 de Diciembre de 2007) tiene la misma funcionalidad que la utilidad Buscar ficheros (gsBuscar) que publiqué el 29 de Agosto y revisé el 1 de Septiembre, es decir, puedes usarla para indicar una "especificación" de ficheros (o archivos) que quieres buscar en un directorio determinado. Esa especificación puede tener caracteres comodines, por ejemplo *.exe buscaría todos los ejecutables.

Lo que tiene de nuevo esta primera revisión de la nueva versión (2.0), además de otras cosas que ahora te comentaré, es que en la especificación esa de lo que quieres buscar puedes indicar varias cosas, siempre que las separes por puntos y comas, por ejemplo, si indicas *.zip; *.rar te buscará todos los ficheros (o archivos) comprimidos que tengan esas extensiones.
Y esa búsqueda la hará en lo directorios que indiques (esto también lo hacía antes) e incluso si quieres que lo haga en los subdirectorios que tenga ese directorio.
La novedad en este caso de los nombres de los directorios, es que también puedes indicar varios directorios separándolos por puntos y comas (para que veas que los puntos y comas no solo se usan en ciertos lenguajes, je, je). De esa forma, puedes indicar que se busque en los directorios E:\Datos; E:\Mis cosas y lo que hará será buscar esa especificación (o especificaciones) en cada uno de esos directorios.

Como ves, solo por estas cosas, esta nueva versión ya te será de más utilidad que la anterior.

Nuevas cosas que hará la utilidad

Pero la nueva versión aún "quiere" hacer más (quiere, pero todavía no lo hace, al menos a día de hoy 9 de Dic del 07), como puede ser que solo busque los ficheros modificados en una fecha indicada o que permita buscar cierto texto en esos ficheros hallados o que pueda incluso cambiar los textos hallados... ya que esas nuevas funcionalidades vendrán en futuras versiones, pero no en esta actual.

Cosas interesantes desde el punto de vista del programador curioso

Pero el que haya publicado ya esta nueva versión de la utilidad, y no haya esperado a que esté más "currada", no es porque haya agregado esas dos cosillas que te comenté antes, que para ser sinceros, son mejoras menores, si no porque en esta nueva versión está hecha con la versión final de Visual Basic 2008 (el proyecto también lo podrás abrir con la versión Express de Visual Basic 2008), y no solo porque esté hecha con la versión 2008 del lenguaje, y por tanto con el .NET Framework 3.5, sino que la "gracia" está en que estoy usando un control de usuario WPF (Windows Presentation Foundation o WinFX) dentro de un formulario normal (de Windows.Forms).

Es decir, he unido funcionalidad de dos mundos totalmente distintos, al menos en la forma de presentar los controles. Ya que los controles de Windows.Forms no se manejan de la misma forma que los controles de WPF, (y si no te fías de lo que te digo, puedes echar un vistazo a los ejemplos que tengo publicados en la sección de WinFX o .NET Framework 3.0), ya que los controles de WPF se escriben usando XAML y los de Windows.Forms, pues de la forma habitual (habitual al menos hasta hace unos meses, ya que desde que apareció el .NET Framework 3.0, las cosas se pueden hacer de dos formas distintas).

Antes de seguir contándote las cosas nuevas, mejor que veas un aspecto del formulario en modo de diseño.

Figura 1. El formulario en modo de diseño
Figura 1. El formulario en modo de diseño

Como puedes observar en la figura 1 no hay nada que te indique que esto no es un formulario normal, salvo si te fijas en los dos "expanders" (esos dos circulitos que hay encima de Buscar y Filtro búsqueda).
En realidad los controles que están en la parte de arriba (que están dentro del recuadro punteado) corresponden a un control de usuario creado con WPF (se crea seleccionando un nuevo elemento del tipo User Control (WPF)) y como puedes suponer, la forma de definir ese control de usuario es por medio de código XAML.

Aquí abajo tienes el código XAML del control de usuario WPF llamado OpcionesBuscar.
He puesto comentarios en el código para que te sea más fácil comprender el porqué de ese código. También he intentado seguir un orden a la hora de definir las propiedades de cada control, y al menos están en este orden: nombre del control, fila/columna en el Grid y después el resto de las propiedades.

Si sabes un poco de cómo se definen los controles WPF por medio de XAML te puedes saltar esta sección y pasar a la siguiente.

Explicación breve del formato XAML

La explicación la he puesto en página aparte, para que sea más fácil de encontrar si alguien no está interesado en esta utilidad de buscar ficheros... o porque en este artículo no muestro ni una sola línea de C#...

 

Explicación del código de esta utilidad

Como te he comentado antes, el control de usuario WPF tiene las partes de la aplicación que define si se va a buscar texto o si se va a reemplazar ese texto por otro diferente, también define otra "zona" de opciones para indicar en qué directorio se buscará y qué "filtro" debe usarse en los ficheros que se van a buscar.
(Ya sabes que esto de buscar y reemplazar texto aún no está implementado, pero lo estará en una futura revisión.)

El haberlo hecho con WPF es porque quería usar un control Expander, ya sabes que ese tipo de control lo que te permite es mostrar u ocultar diferentes opciones, así que... como en Windows Vista eso es un "estándar" de diseño, pues me dije (porque yo algunas veces hablo conmigo mismo y me digo cosas, je, je; valeeee, en realidad no me lo digo, sino que lo pienso y es como si me lo dijera yo a mi mismo): Voy a hacerlo con varios Expander que así es más "cool" (o molón).

La creación de controles WPF la puedes hacer directamente en una aplicación "normal", es decir, no tienes porqué crear el control de forma separada, compilarlo y después usarlo. También lo puedes hacer así, pero en este caso, simplemente lo que he hecho es agregar un elemento nuevo de ese tipo y después he definido el contenido y la funcionalidad que yo quiero en este caso particular.

La única pega que tengo con este control WPF en particular es que define ciertos eventos para habilitar ciertos controles, por ejemplo, cuando no está seleccionada la opción de Buscar (chkBuscar), tengo que deshabilitar todos los controles de esa "zona" del control, además de cambiar el texto mostrado en la "cabecera" (propiedad Header) del Expander correspondiente; y al tener esos eventos funcionando, pues el diseñador de Visual Studio 2008 se hace un lío y me da error...
Para evitar esos errores del diseñador, lo que hago en ese control, es definir los manejadores de evento en una propiedad que asigno cuando la aplicación está en ejecución. Y cuando la aplicación se acaba, quito esos manejadores de eventos, (esto último no es necesario, pero... lo he hecho).
En particular los eventos que asigno manualmente son los que controlan el estado de los controles CheckBox.
El código que se encarga de hacer esto que te comento está en la propiedad llamada EnEjecucion (puedes ver el código ahí abajo, en la parte del código del control de usuario OpcionesBuscar).

Como puedes ver en el código del control, (independiente de que se asignen manualmente los "manejadores de eventos"), también uso la variable privada de esa propiedad (m_EnEjecucion) para saber si deben hacerse comprobaciones sobre los controles o no, esto es algo habitual que siempre habría que hacer, ya que muchas veces, esos eventos se producen mientras se están creando los controles (y asignando los valores a las propiedades que producen el evento ese en concreto), por tanto, puede ocurrir que el resto de controles que se están usando aún no estén creados.
Si quieres probarlo (o comprobarlo), puedes quitar (o comentar) la primera línea de código de los métodos expanderBuscar_Collapsed y expanderBuscar_Expanded y verás que bonito error te dará al ejecutar la aplicación. La razón de ese error es porque se intenta acceder al control gridTexto y ese control aún está en el limbo, es decir, aún no existe (sí, tienes razón, algunos siempre están -o estamos- en el limbo, y aún así, existimos, je, je, je).

Cosas a destacar del código del control OpcionesBuscar

Del código del control WPF, quisiera que te fijaras, además de lo que te comentaba sobre que no entre la ejecución en los métodos de los eventos cuando no deben entrar, la forma de asignar nuevos directorios al usar el método del botón btnExaminarDir. Como te he comentado, los directorios a examinar pueden ser varios, estando separados por puntos y comas, por tanto, se tiene en cuenta ese "detalle" de forma que al añadir un nuevo valor, si ya había algo en el texto del combo correspondiendo (cboDir), se añade al final, añadiendo un punto y coma. De esa forma es más fácil agregar nuevos directorios.
Por supuesto, cuando se pulsa en ese botón se tiene en cuenta si hay varios valores separados por puntos y comas, de ser así, se usa el primero de esos valores. De eso se encarga la parte de la comprobación
If Me.cboDir.Text.Contains(";") Then.

Debido a que desde el formulario (una opción del menú Fichero) necesito llamar al método del evento Click del botón Examinar, he creado un método público para hacer eso (btnExaminarClick), aunque también podría haber cambiado la visibilidad del método del evento Click, pero... solo es cuestión de gustos...

En cuanto al "porqué" de la comprobación que hay en el evento del chkBuscar:

If chkPoner.Tag IsNot Nothing AndAlso CBool(chkPoner.Tag) = False Then 

Esto es porque en el formulario asigno un valor False a la propiedad Tag del control chkPoner, ya que aún no está implementada la funcionalidad y por tanto, no tiene ningún motivo que se puedan usar los controles que están relacionados con esa opción.
Aunque la verdad es que eso no hace falta, ya que desde el propio formulario principal he deshabilitado el chkBuscar, ya que tampoco está implementada la funcionalidad de buscar texto en los ficheros... pero más que nada me ha servido para saber si todo va funcionando como espero que funcione.

Por último, resaltar que en los cuatro eventos de los Expander (dos para cada control, según se oculten o muestren), lo que hago es mostrar u ocultar el Grid asociado con cada control Expander, con idea de que el StackPanel actúe visualmente sobre esos controles, así se moverá hacia arriba el Expander de los ficheros cuando el Expander de la búsqueda se contraiga.
Además produzco (o lanzo) el evento ExpanderExpandedChanged con idea de que el formulario se entere de que hay que tener en cuenta el nuevo tamaño o espacio ocupado por la parte visual del control y así poder posicionar adecuadamente el ListView que hay debajo del control de usuario.

En la siguiente figura puedes ver la aplicación en ejecución con el primer Expander contraído (ocultando las opciones de búsqueda de texto) y como ves, el ListView se adapta al nuevo tamaño.

Figura 2. La utilidad en ejecución con un Expander contraído
Figura 2. La utilidad en ejecución con un Expander contraído

 

Nota (ejercicio a hacer antes de ver el código del proyecto completo):
En el código mostrado si se suelta un fichero o directorio en el formulario (o el control de usuario) se asigna ese valor al texto del combo de los directorios.
Como ejercicio te propongo que el fichero soltado se agregue a lo que ya haya (como al usar el botón de examinar).
Te recuerdo (por si no quieres ver la solución) que en el código del proyecto ya está ese código, así que... si quieres hacerlo por tu cuenta, no mires el código del proyecto completo.

En el código del proyecto en realidad lo que se hace es añadir TODOS los ficheros/directorios que se arrastren y suelten, pero también tienes el código de cómo añadir solo el primero de esos ficheros.

 

Explicación del código del formulario

Del código del formulario te voy a explicar bien poco, ya que he puesto los suficientes comentarios como para que sepas que se hace en cada caso.

Aquí abajo tienes el código del formulario.

Recuerda el ejercicio comentado antes, ya que en el evento DraqDrop también habría que tener en cuenta lo que quieres agregar al texto del combo.

Resaltarte un par de cosas que te pueden resultar interesantes (al menos desde mi punto de vista, claro):

Cuando arrastras y sueltas cosas en el combo del directorio (en realidad en el combo del directorio no te deja soltar, pero para el caso es lo mismo), es posible que lo que sueltes sea un fichero en lugar de un directorio, e incluso es posible que escribas el nombre de un fichero, y en esos casos (al menos en los que he probado), lo que hago es detectar que el directorio no existe y buscar el nombre del directorio que debería usarse, e intentar usar ese nombre de directorio (esas comprobaciones las hago en el código del evento Click del botón Buscar).

If di.Exists = False _
AndAlso di.Attributes = FileAttributes.Archive Then
    di = New DirectoryInfo(Path.GetDirectoryName(di.FullName))
End If
If di.Exists Then
    recorrerDir(di)
End If

Y si el caso de que ese directorio no exista es porque has agregado ficheros, es muy posible que agregues varios ficheros de un mismo directorio o que añadas el mismo directorio más de una vez.
En esos casos (en los que el mismo directorio está repetido) lo que pasaría es que se examinaría el mismo directorio más de una vez, y por tanto, podría haber ficheros repetidos. Así que, para evitar esas repeticiones de directorios y evitar hacer el mismo trabajo más de una vez, pues he usado una colección llamada dirExaminados a la que voy agregando cada directorio, pero solo se añade si no existe en la colección, y en caso de que exista, pues... simplemente se sale del método recorrerDir (que es donde se hace la comprobación).
El código usado es el siguiente:

If dirExaminados.Contains(di.FullName.ToLower()) Then
    Exit Sub
End If
dirExaminados.Add(di.FullName.ToLower())

Por supuesto, el contenido de esa colección se "limpia" antes de empezar a procesar las cosas (es decir, cada vez que pulsas en el botón Buscar).

Además de esto que te acabo de contar, también se tiene en cuenta que se puedan indicar varios directorios y varias especificaciones o filtros, con idea de que en una misma búsqueda puedas tener en cuenta más de un directorio y más de un fichero a buscar (o tener en cuenta en la búsqueda).

 

Conclusiones

Espero que te sea de utilidad y te sirva para algo más que para usar simplemente la utilidad... que es de lo que se trata todo esto que te estoy contando, y que aunque no te lo crea, lo empecé a escribir a las 03.42 (aunque en realidad debería empezar a contar a eso de las 14 horas, ya que a las 03.42 lo que hice fue preparar la página para escribir, pero después fui a llevar a mi hijo al aeropuerto y cuando volví me acosté y en realidad hasta eso de las 2 de la tarde no empecé "en serio") y lo he acabado a las 22.55, (en realidad, con los ajustes que le he hecho, ya son es la 01.06 del lunes día 10), por tanto, han sido más de 9 horas "efectivas" las que he tardado en dejar listo este artículo (y el de la explicación del formato XAML) (sí, ya lo sé, es que soy mu pamplinas, je, je).

Así que... me gustaría que todo ese tiempo empleado te sea de utilidad guiño.

 

Más abajo tienes el ZIP con el proyecto completo para Visual Basic 2008, ese proyecto lo puedes abrir tanto con la versión normal de Visual Studio 2008 como con la versión Express de Visual Basic 2008.

 

Si te preguntas porqué no hay código de C#...

Bueno... decirte que es muy posible que a partir de ahora no ponga siempre los ejemplos en Visual Basic y en C#, (algo que he estado haciendo en todos (o casi todos) mis artículos desde Enero de 2001), ya que... (¿cómo decirlo para que nadie se moleste?), bueno... a ver... es que como últimamente hay una corriente de comentarios (aún más fuerte de lo habitual, ¿será por el cambio climático?) que dicen que los que usamos Visual Basic sabemos menos que los que usan C#, pues... por lógica hay que deducir que los que usan C# son más listos o saben más que los que usamos Visual Basic, así que... como los de C# son más listos, pues seguro que sabrán convertir el código de VB a C# sin problemas, e incluso no les hará falta ni convertirlo, porque ya sabrán hacerlo... así que... si eres de los que están en el grupo que usa C# para escribir sus programas, pues... por ahora no estará este ejemplo para C#... ¡lo siento!

 

Nos vemos.
Guillermo

P.S.
Si quieres hacer algún comentario sobre este artículo, por favor usa el siguiente link para hacerlo en mis foros:
Artículo: gsBuscarTexto (v2.0 para VB2008)
Gracias.



Código Xaml El código XAML del control de usuario

El código XAML del diseño del control de usuario WPF

El código XAML del control de usuario WPF está: gsBuscarTexto.OpcionesBuscar.xaml.

 

Código para Visual Basic.NET (VB.NET) El código para Visual Basic

El código del control de usuario WPF OpcionesBuscar

El código de Visual Basic para el control de usuario WPF está en: gsBuscarTexto.OpcionesBuscar.xaml.vb.

 

El código fuente del formulario

El código fuente para Visual Basic del formulario principal está en: gsBuscarTexto.Form1.vb.

 


Código de ejemplo (comprimido):

Fichero con el proyecto para Visual Basic 2008: gsBuscarTexto_src_2_0_0_3.zip - 49.30 KB

Además de todo el código (incluido el control de usuario WPF), también se incluye el ejecutable, pero para usarlo debes tener el runtime de .NET Framework 3.5.

(MD5 checksum: 631AA18E83F2A9793687B03DA4E961BD)

Nota del 27/Dic/07:
Este es el código fuente de la versión 2.0.0.3, ahora hay nuevas revisiones y en la página de la última revisión está el código fuente más actualizado, pero este no lo sobrescribo porque en las nuevas revisiones no se usa el control creado en WPF, así que... por si te da curiosidad de cómo usarlo y esas cosas, lo voy a dejar, aunque le voy a cambiar el nombre al fichero, con idea de que no lo sobrescriba en las nuevas revisiones.
El link este que te acabo de poner es el del día 27 de Diciembre, pero es posible que cuando leas esto ya haya nuevas versiones. Al principio de esta página siempre estará el link a la última revisión, con idea de que no te pierdas nada.
De nada

 


 


La fecha/hora en el servidor es: 22/12/2024 17:19:33

La fecha actual GMT (UTC) es: 

©Guillermo 'guille' Som, 1996-2024