none
Textbox de busqueda

    Pregunta

  • Hola que tal, escribo para hacerles la siguiente consulta:

    En un formulario tengo un textbox donde a medida que ingreso caracteres me va mostrando en un datagridview lo encontrado en la BD. 

    Pero me gustaria hacer un textbox como los de los navegadores web o de la mayoria de aplicaciones modernas, es decir que tenga en el TextBox por defecto la palabra "Buscar"  y que cuando ingreses algun caracter se borre, y que cuando uno borre lo escrito vuelva a aparecer la palabra "Buscar".

    Yo lo que habia hecho era ponerle el texto "Buscar" en la propiedad text del textbox y luego que cuando tenga el control sobre el textbox usar "cleartextbox()" y luego cuando se borre lo buscado usar textbox.text = "Buscar", pero cuando hago esto el datagrid me muestra inmediatamente los resultados de "buscar" como si se tratara de una busqueda, de forma que no funciona.

    Supongo que habrá una forma correcta de hacer esto. Espero que se entienda y que alguien me pueda ayudar.

    Gracias de antemano, saludos.

    martes, 20 de septiembre de 2016 2:09

Respuestas

  • "Joel C. Naupa Crispín" escribió:

    > Lo que deseas es crear un placeholder, puedes hacer algo como esto :
    >
    > Dim buscar As String = "Buscar ..."
    >
    > Private Sub TextBox1_Leave(sender As Object, e As EventArgs) Handles TextBox1.Leave
    >     Dim txt As TextBox = TryCast(sender, TextBox)
    >     If txt.Text.Trim() = String.Empty Then
    >         txt.Text = buscar
    >         txt.ForeColor = Color.Gray
    >     End If
    > End Sub

    Hola, Joel C.:

    En primer lugar te pido disculpas por mi intromisión, pero quisiera comentarte el problema que yo veo con el código que has indicado, y simplemente es que a la propiedad Text del control TextBox le estás asignado el valor del campo llamado buscar, cuando en un control TextBox del tipo PlaceHolder, en realidad el valor de la propiedad Text debería ser una cadena de longitud cero (String.Empty o ""), que será cuando se muestre el texto informativo (Buscar ..., Escribir ..., etc.) en el control TextBox.

    Y eso se consigue mediante una simple llamada a la función SendMessage de la API de Windows pasándole el valor de la constante EM_SETCUEBANNER, tal y como muestra un ejemplo que encontrarás en la tercera respuesta de la siguiente conversación indicada por Williams Morales en su respuesta, de ahí que la haya propuesto como respuesta:

        Adding placeholder text to textbox

    Es decir, cuando el control TextBox pierda el foco, y siempre que el valor de la propiedad Text del control TextBox sea una cadena de longitud cero, mostrar el valor del campo buscar:

    Private buscar As String = "Buscar ..."

    If (TextBox1.Text = String.Empty) Then SendMessage(TextBox1.Handle, EM_SETCUEBANNER, 0, buscar)
    End If


    Y cuando obtenga el foco, y siempre que el valor de la propiedad Text del control TextBox también sea una cadena de longitud cero, pasarle una cadena de longitud cero a la función SendMessage:   

     

    If (TextBox1.Text = String.Empty) Then
    SendMessage(TextBox1.Handle, EM_SETCUEBANNER, 0, String.Empty)
    End If


    Por supuesto, hace falta la declaración de la función SendMessage y de la constante EM_SETCUEBANNER:

        Imports System.Runtime.InteropServices
    
        Private Const EM_SETCUEBANNER As Integer = &H1501
    
        <DllImport("user32.dll", CharSet:=CharSet.Auto)>
        Private Shared Function SendMessage(hWnd As IntPtr, msg As Integer, wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> lParam As String) As Int32
        End Function

    Un saludo y disculpa de nuevo la intromisión


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.






    martes, 20 de septiembre de 2016 15:25
    Moderador
  • Hola The High Road,

    Supongo que haces el filtrado del TextBox mediante su evento KeyPress o TextChanged, ahí es donde tendrías que validar si el TextBox tiene el valor "Buscar" o no para hacer el filtro.

    Lo que deseas es crear un placeholder, puedes hacer algo como esto :

        Dim buscar As String = "Buscar ..."
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            TextBox1.Text = buscar
            TextBox1.ForeColor = Color.Gray
        End Sub
    
        Private Sub TextBox1_Enter(sender As Object, e As EventArgs) Handles TextBox1.Enter
            Dim txt As TextBox = TryCast(sender, TextBox)
            If txt.Text.Equals(buscar) Then
                txt.Text = String.Empty
                txt.ForeColor = SystemColors.WindowText
            End If
        End Sub
    
        Private Sub TextBox1_Leave(sender As Object, e As EventArgs) Handles TextBox1.Leave
            Dim txt As TextBox = TryCast(sender, TextBox)
            If txt.Text.Trim() = String.Empty Then
                txt.Text = buscar
                txt.ForeColor = Color.Gray
            End If
        End Sub

    Resultado :

    Al momento de hacer el filtro usas el .Equals() para saber si el TextBox contiene el "placeholder" o no.

    Saludos.


    JC NaupaCrispín
    Lima - Perú

    La magia no existe, la programación SI

    martes, 20 de septiembre de 2016 3:02
  • The High Road,

    Hay cientos de lugares en internet donde podrás encontrar como implementar el atributo PlaceHolder en un objeto de tipo TextBox (WinForm), te dejo algunos enlaces:

    Adding placeholder text to textbox

    TextBox with Placeholder

    How to add a placeholder in a Windows Forms textbox

    Respecto a evitar el filtro cuando se muestre la marca PlaceHolder, creo que es tan simple como lanzar la búsqueda únicamente cuando el valor de la propiedad 'Text' sea distinto a 'Buscar'.


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    martes, 20 de septiembre de 2016 3:05

Todas las respuestas

  • Hola The High Road,

    Supongo que haces el filtrado del TextBox mediante su evento KeyPress o TextChanged, ahí es donde tendrías que validar si el TextBox tiene el valor "Buscar" o no para hacer el filtro.

    Lo que deseas es crear un placeholder, puedes hacer algo como esto :

        Dim buscar As String = "Buscar ..."
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            TextBox1.Text = buscar
            TextBox1.ForeColor = Color.Gray
        End Sub
    
        Private Sub TextBox1_Enter(sender As Object, e As EventArgs) Handles TextBox1.Enter
            Dim txt As TextBox = TryCast(sender, TextBox)
            If txt.Text.Equals(buscar) Then
                txt.Text = String.Empty
                txt.ForeColor = SystemColors.WindowText
            End If
        End Sub
    
        Private Sub TextBox1_Leave(sender As Object, e As EventArgs) Handles TextBox1.Leave
            Dim txt As TextBox = TryCast(sender, TextBox)
            If txt.Text.Trim() = String.Empty Then
                txt.Text = buscar
                txt.ForeColor = Color.Gray
            End If
        End Sub

    Resultado :

    Al momento de hacer el filtro usas el .Equals() para saber si el TextBox contiene el "placeholder" o no.

    Saludos.


    JC NaupaCrispín
    Lima - Perú

    La magia no existe, la programación SI

    martes, 20 de septiembre de 2016 3:02
  • The High Road,

    Hay cientos de lugares en internet donde podrás encontrar como implementar el atributo PlaceHolder en un objeto de tipo TextBox (WinForm), te dejo algunos enlaces:

    Adding placeholder text to textbox

    TextBox with Placeholder

    How to add a placeholder in a Windows Forms textbox

    Respecto a evitar el filtro cuando se muestre la marca PlaceHolder, creo que es tan simple como lanzar la búsqueda únicamente cuando el valor de la propiedad 'Text' sea distinto a 'Buscar'.


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    martes, 20 de septiembre de 2016 3:05
  • "Joel C. Naupa Crispín" escribió:

    > Lo que deseas es crear un placeholder, puedes hacer algo como esto :
    >
    > Dim buscar As String = "Buscar ..."
    >
    > Private Sub TextBox1_Leave(sender As Object, e As EventArgs) Handles TextBox1.Leave
    >     Dim txt As TextBox = TryCast(sender, TextBox)
    >     If txt.Text.Trim() = String.Empty Then
    >         txt.Text = buscar
    >         txt.ForeColor = Color.Gray
    >     End If
    > End Sub

    Hola, Joel C.:

    En primer lugar te pido disculpas por mi intromisión, pero quisiera comentarte el problema que yo veo con el código que has indicado, y simplemente es que a la propiedad Text del control TextBox le estás asignado el valor del campo llamado buscar, cuando en un control TextBox del tipo PlaceHolder, en realidad el valor de la propiedad Text debería ser una cadena de longitud cero (String.Empty o ""), que será cuando se muestre el texto informativo (Buscar ..., Escribir ..., etc.) en el control TextBox.

    Y eso se consigue mediante una simple llamada a la función SendMessage de la API de Windows pasándole el valor de la constante EM_SETCUEBANNER, tal y como muestra un ejemplo que encontrarás en la tercera respuesta de la siguiente conversación indicada por Williams Morales en su respuesta, de ahí que la haya propuesto como respuesta:

        Adding placeholder text to textbox

    Es decir, cuando el control TextBox pierda el foco, y siempre que el valor de la propiedad Text del control TextBox sea una cadena de longitud cero, mostrar el valor del campo buscar:

    Private buscar As String = "Buscar ..."

    If (TextBox1.Text = String.Empty) Then SendMessage(TextBox1.Handle, EM_SETCUEBANNER, 0, buscar)
    End If


    Y cuando obtenga el foco, y siempre que el valor de la propiedad Text del control TextBox también sea una cadena de longitud cero, pasarle una cadena de longitud cero a la función SendMessage:   

     

    If (TextBox1.Text = String.Empty) Then
    SendMessage(TextBox1.Handle, EM_SETCUEBANNER, 0, String.Empty)
    End If


    Por supuesto, hace falta la declaración de la función SendMessage y de la constante EM_SETCUEBANNER:

        Imports System.Runtime.InteropServices
    
        Private Const EM_SETCUEBANNER As Integer = &H1501
    
        <DllImport("user32.dll", CharSet:=CharSet.Auto)>
        Private Shared Function SendMessage(hWnd As IntPtr, msg As Integer, wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> lParam As String) As Int32
        End Function

    Un saludo y disculpa de nuevo la intromisión


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.






    martes, 20 de septiembre de 2016 15:25
    Moderador
  • Estimado Sr. Enrique M. Montejo,

    Pierda el cuidado, la crítica constructiva es muy importante para evolucionar como desarrollador, además de ayudar a mejorar mi conocimiento y el de futuros usuarios que puedan leer el hilo, todo sea bienvenido :) .

    - Respondiendo a su comentario :

    [-] ... el valor de la propiedad Text debería ser una cadena de longitud cero (String.Empty o ""), que será cuando se muestre el texto informativo (Buscar ..., Escribir ..., etc.) en el control TextBox.

    Tengo claramente el uso del Placeholder y tiene toda la razón, el control TextBox debe mostrar el texto informativo y a la vez si se obtiene el valor este debe devolver un valor vacío valga la redundancia.

    En el link que usted hace referencia, la respuesta que el usuario marcó como correcta es haciendo uso de los eventos GotFocus/LostFocus. Personalmente cuando busco respuestas en un hilo, siempre me fijo en la que ha sido marcada o la que tenga mayor cantidad de votaciones, ya que significa que esa respuesta dio solución a la pregunta planteada, por lo que dejé de lado usar el api de windows.

    Con respecto a su ejemplo, usted menciona que se tiene que agregar el SendMessage cuando se obtenga o pierda el foco del control, pero esto es realmente necesario ?

    Ya que lo implementé de la siguiente manera y no tengo problemas.

        Private buscar As String = "Buscar ..."
        Private Const EM_SETCUEBANNER As Integer = &H1501
    
        <DllImport("user32.dll", CharSet:=CharSet.Auto)>
        Private Shared Function SendMessage(hWnd As IntPtr, msg As Integer,
               wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> lParam As String) As Int32
        End Function
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            SendMessage(TextBox1.Handle, EM_SETCUEBANNER, 0, buscar)
        End Sub

    E inclusive validé el contenido al mostrar el placeholder, lo cual ratifica que sería la mejor opción.

    La verdad nunca había usado DllImport, por lo que no puedo asegurar que sea la mejor opción solo porque me funcione, en caso no sea la forma correcta agradecería hacérmelo saber.

    Saludos.


    JC NaupaCrispín
    Lima - Perú

    La magia no existe, la programación SI

    martes, 20 de septiembre de 2016 23:32
  • "Joel C. Naupa Crispín" escribió:

    > Con respecto a su ejemplo, usted menciona que se tiene que agregar el
    > SendMessage cuando se obtenga o pierda el foco del control, pero esto
    > es realmente necesario ?

    Si queremos simular un control del tipo "PlaceHolder", entiendo que esos serían los eventos idóneos para invocar a la función SendMessage: al obtener el foco para eliminar el texto informativo del control, y al perder el foco el control para mostrar de nuevo el texto informativo si procede.

    > Ya que lo implementé de la siguiente manera y no tengo problemas.
    >
    > Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    >    SendMessage(TextBox1.Handle, EM_SETCUEBANNER, 0, buscar)
    > End Sub

    Siempre que invoques a la función SendMessage, como a cualquier otra función diferente tanto de la API de Windows como de nuestra propia cosecha, pasándole los valores de los parámetros requeridos, no vas a tener ningún problema, con independencia que la llames desde el evento Load o desde cualquier otro evento, propiedad o método de un formulario, de un control o de una clase propia.

    Si llamas a la función SendMessage desde el evento Load pasándole el valor del campo llamado buscar, estaría correcto si estás completamente seguro que el valor de la propiedad Text del control TextBox es una cadena de longitud cero. Pero, ¿y si no es así?. Entiendo que lo correcto sería verificar siempre el valor de la propiedad Text para establecer el texto informativo, se llame a la función SendMessage desde el evento, propiedad o método que hallamos elegido:

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            ' Si el valor de la propiedad Text es una cadena de longitud cero,
            ' mostramos el texto informativo en el control TextBox.
            '
            If (TextBox1.Text = String.Empty) Then
                SendMessage(TextBox1.Handle, EM_SETCUEBANNER, 0, buscar)
            End If
    
        End Sub
    

    Ten en cuenta que el usuario ha podido establecer en tiempo de diseño el valor de la propiedad Text desde la Ventana de Propiedades, o puede ser que el control TextBox se encuentre enlazado a un objeto de datos para que automáticamente muestre el valor del campo del registro actual de un objeto DataTable, por poner unos ejemplos, de ahí que haya que comprobar el valor de la propiedad Text antes de llamar a la función SendMessage.

    > La verdad nunca había usado DllImport, por lo que no puedo asegurar que
    > sea la mejor opción solo porque me funcione, en caso no sea la forma
    > correcta agradecería hacérmelo saber.

    En el mundo anterior a .NET, la verdad es que era raro ver un programa que no hiciera uso de llamadas a la API de Windows. Hoy en día, afortunadamente son muchas menos las veces que los programadores tienen que hacer uso de ellas de una manera directa, lo que no quiere decir que la infraestructura del propio marco de trabajo de .NET se encargue de hacer finalmente dichas llamadas, digamos que de una manera indirecta o transparente a nuestro código fuente.

    Si el marco de trabajo de .NET nos pone a nuestra disposición clases cuyos métodos nos evitan tener que recurrir directamente a la API de Windows, entiendo que tendríamos que utilizar dichos métodos; en caso contrario, tendríamos que ser nosotros los que directamente tendríamos que efectuar dichas llamadas. Mientras sepamos declarar correctamente la firma de la función API y le pasemos los valores adecuados, pues no vamos a tener ningún problema ni se va a ver penalizado por ello el rendimiento de nuestra aplicación. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    miércoles, 21 de septiembre de 2016 9:24
    Moderador
  • Hola @The High Road

    Lo que podrías hacer es personalizar un control TextBox para ponerle una propiedad de marca de agua Custom TextBox with Watermark

    Después filtrar como lo has pensado Filtrar datos en DataGridView

    Esta en C# pero puedes usar convertidores de código Convertir de C# a Visual Basic .NET

    Convert C# to VB.NET

    He modificado un controlo TextBox en el cual una de sus propiedades es Watermark te envio la dll TextBoxt modificado

    Lo que tienes que hacer es agregar la dll GlobalTech.TextBoxControl.dll en una carpeta dentro de tu proyecto y agregar la referencia a tu proyecto y en tu ToolBox creas una nueva pestaña y agregas los elementos le das la ruta de la dll y te apareceran dos controles uno de ellos es el TextBox, ya pronto hare un manual de este control que he modificado que sera de mucha ayuda para los desarrolladores que trabajan con windows forms.



    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú


    • Editado Pedro Ávila miércoles, 21 de septiembre de 2016 13:26 ...
    miércoles, 21 de septiembre de 2016 13:25
  • Hola muchas gracias a todos los que se tomaron el tiempo de ayudarme!!! Pude solucionar mi problema, y lo mejor de todo es que aprendí un monton!
    sábado, 24 de septiembre de 2016 3:18
  • "Joel C. Naupa Crispín" escribió:

    > Con respecto a su ejemplo, usted menciona que se tiene que agregar el SendMessage
    > cuando se obtenga o pierda el foco del control, pero esto es realmente necesario ?
    >
    > Ya que lo implementé de la siguiente manera y no tengo problemas.
    >
    >    Private buscar As String = "Buscar ..."
    >
    >    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    >        SendMessage(TextBox1.Handle, EM_SETCUEBANNER, 0, buscar)
    >    End Sub

    Leyendo de nuevo el contenido de tu respuesta, me estoy dando cuenta que me parece a mí que no supe interpretarlo bien el pasado miércoles, porque yo interpreté que no tenías problemas para llamar a la función SendMessage desde el evento Load del formulario, y ahora pienso que no te referías a eso. :-(

    Si por "no tener problemas" te refieres a que desde el evento Load has hecho que el control TextBox se comporte como si fuera un tipo de control "PlaceHolder" (o Cue Banner, que entiendo debería ser un concepto más apropiado), invocando a la función SendMessage para pasarle el texto informativo del control, efectivamente no es necesario hacerlo desde el evento Leave (se pierde el foco) o Enter (se obtiene el foco), porque mientras que el texto especificado no sea una cadena de longitud cero, el control TextBox se comportará como PlaceHolder o Cue Banner.

    Cuando deseemos que el control TextBox deje ese comportamiento es cuando hay que llamar de nuevo a la función SendMessage con el valor EM_SETCUEBANNER pasándole una cadena de longitud cero en el parámetro lParam.

    Utilizar los eventos Leave y Enter tendrían sentido si deseas personalizar la fuente y el color de primer plano de la nota, indicio o consejo del contenido del texto informativo que aparece en el control cuando éste pierde el foco, cuestión ésta última que, salvo que yo esté equivocado, no se podrá implementar en el control de edición si a éste se le ha establecido el indicador EM_SETCUEBANNER. O también, si deseas que el control TextBox sea de múltiples líneas (Multiline = True), necesariamente tendrá que perder la condición de Cue Banner, ya que un control de éstas características no permite múltiples líneas.

    Pero si no es así, con llamar a la función SendMessage desde el evento Load pasándole el valor EM_SETCUEBANNER y una cadena alfanumérica que no sea de longitud cero, es más que suficiente.

    Espero que ahora haya sabido interpretar bien el contenido de tu mensaje. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.




    sábado, 24 de septiembre de 2016 16:25
    Moderador