none
Eventos que se producen cuando un combobox está desplegado

    Pregunta

  • Un saludo.

    Me gustaría saber si hay algún evento en un combo , cuando una vez desplegada su lista,  el usuario pasa el puntero del ratón sobre la misma, pero sin hacer click todavía sobre ninguno de los elementos. En ese punto, me interesa tener información sobre el ítem que está señalando el puntero.

    Gracias anticipadas.


    Miguel Ángel Muñoz

    martes, 30 de agosto de 2016 20:24

Respuestas

  • Miguel Ángel Muñoz,


    Te recomiendo que leas el siguiente artículo, creo que contiene lo que requieres: ComboBox firing events when hovering on the dropdown list

    "...Have you ever wanted live feedback from your ComboBox? Have you ever wanted it to be able to let you know which item the user is hovering over in the dropdown list before it is clicked? In this article, I will show how to inherit a custom combo box control which will fire events when the mouse cursor is hovering over the items in the dropdown list."


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.

    martes, 30 de agosto de 2016 21:28
  • "Miguel Ángel Muñoz" escribió:

    > Concretamente es aqu´´i donde se produce el error:
    >
    >        Public Event Hover As HoverEventHandler
    >
    >        Protected Overridable Sub OnHover(e As HoverEventArgs)
    >            Dim handler As HoverEventHandler = Hover
    >            ' Invokes the delegates.
    >            RaiseEvent handler(Me, e)
    >        End Sub
    >
    > El texto del error es: " 'Public Event Hover(sender As Object, e As HoverEventArgs)'
    > es un evento y no se puede llamar directamente. Utilice la instrucción RaiseEvent
    > para provocar un evento."

    Hola, Miguel Ángel:

    Sustituye el método OnHover por éste otro para desencadenar simplemente el evento Hover:

            Protected Overridable Sub OnHover(e As HoverEventArgs)
                RaiseEvent Hover(Me, e)
            End Sub

    Ten en cuenta que a éste método solamente lo llama la siguiente línea de código existente en el método WndProc:

            Dim e As New HoverEventArgs()
            e.itemIndex = If((onScreenIndex > Me.Items.Count - 1), Me.Items.Count - 1, onScreenIndex)
            OnHover(e)

    Por tanto, al método OnHover le está pasando una instancia de la clase HoverEventArgs válida, que es la que tienes que incluir en la instrucción RaiseEvent para desencadenar el evento Hover.

    Y en el formulario que contiene un control del tipo [Custom].MyComboBox, instalarías el controlador para el evento Hover:

        Private Sub MyComboBox1_Hover(sender As Object, e As HoverEventArgs) Handles MyComboBox1.Hover
    
            Dim cb As Custom.MyComboBox = DirectCast(sender, Custom.MyComboBox)
    
            Label1.Text = String.Format("Item {0} = {1}", e.itemIndex.ToString(), cb.Items(e.itemIndex))
    
        End Sub
    

    Por cierto, si tienes la instrucción Option Strict activada, que es lo recomendable, busca la siguiente línea que aparece en negrita en el método WndProc:

        If Me.DropDownStyle = ComboBoxStyle.Simple Then
            onScreenIndex += simpleOffset
            If (onScreenIndex > ((Me.DropDownHeight / Me.ItemHeight) + simpleOffset)) Then
                onScreenIndex = ((Me.DropDownHeight / Me.ItemHeight) + simpleOffset - 1)
            End If
        End If

    Y la sustituyes por la siguiente:

        onScreenIndex = CInt(((Me.DropDownHeight / Me.ItemHeight) + simpleOffset - 1))

    Un saludo


    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, 31 de agosto de 2016 18:55
    Moderador

Todas las respuestas

  • Miguel Ángel Muñoz,


    Te recomiendo que leas el siguiente artículo, creo que contiene lo que requieres: ComboBox firing events when hovering on the dropdown list

    "...Have you ever wanted live feedback from your ComboBox? Have you ever wanted it to be able to let you know which item the user is hovering over in the dropdown list before it is clicked? In this article, I will show how to inherit a custom combo box control which will fire events when the mouse cursor is hovering over the items in the dropdown list."


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.

    martes, 30 de agosto de 2016 21:28
  • Gracias, Williams. He descargado la aplicaci´´on de ejemplo y es exactamente lo que necesito. El problema es que el c´´odigo fuente est´´a  en C y cuando lo convierto a Visual me da un error que me impide compilarlo. Pongo aqu´´i el c´´odigo resultante despu´´es de utilizar uno de los conversores que existen por ah´´i:

    Imports System.Collections.Generic
    Imports System.Windows.Forms
    Imports System.Runtime.InteropServices
    Imports System.Drawing
    
    Namespace [Custom]
        ''' <summary>
        ''' Derived ComboBox that shows current position of the cursor inside the drop down
        ''' as it's actually moving around in there.  This combobox will raise the custom
        ''' event we have defined above whenever a new item is hovered over in the drop down list
        ''' </summary>
        Class MyComboBox
            Inherits ComboBox
            ' Internal variables to hold the mouse position and the control
            ' position for calculating whether the mouse is inside the drop down
            ' and whether we scrolled with the mouse inside the drop down
            Private yPos As Integer = 0
            Private xPos As Integer = 0
            Private scrollPos As Integer = 0
            Private xFactor As Integer = -1
            Private simpleOffset As Integer = 0
    
            ' Import the GetScrollInfo function from user32.dll
            <DllImport("user32.dll", SetLastError:=True)> _
            Private Shared Function GetScrollInfo(hWnd As IntPtr, n As Integer, ByRef lpScrollInfo As ScrollInfoStruct) As Integer
            End Function
    
            ' Win32 constants
            Private Const SB_VERT As Integer = 1
            Private Const SIF_TRACKPOS As Integer = &H10
            Private Const SIF_RANGE As Integer = &H1
            Private Const SIF_POS As Integer = &H4
            Private Const SIF_PAGE As Integer = &H2
            Private Const SIF_ALL As Integer = SIF_RANGE Or SIF_PAGE Or SIF_POS Or SIF_TRACKPOS
    
            Private Const SCROLLBAR_WIDTH As Integer = 17
            Private Const LISTBOX_YOFFSET As Integer = 21
    
            ' Return structure for the GetScrollInfo method
            <StructLayout(LayoutKind.Sequential)> _
            Private Structure ScrollInfoStruct
                Public cbSize As Integer
                Public fMask As Integer
                Public nMin As Integer
                Public nMax As Integer
                Public nPage As Integer
                Public nPos As Integer
                Public nTrackPos As Integer
            End Structure
    
            Public Event Hover As HoverEventHandler
    
            Protected Overridable Sub OnHover(e As HoverEventArgs)
                Dim handler As HoverEventHandler = Hover
    
                ' Invokes the delegates. 
                RaiseEvent handler(Me, e)
            End Sub
    
            'Capture messages coming to our combobox
            Protected Overrides Sub WndProc(ByRef msg As Message)
                'This message code indicates the value in the list is changing
                '32 is for DropDownStyle == Simple
                If (msg.Msg = 308) OrElse (msg.Msg = 32) Then
                    Dim onScreenIndex As Integer = 0
    
                    ' Get the mouse position relative to this control
                    Dim LocalMousePosition As Point = Me.PointToClient(Cursor.Position)
                    xPos = LocalMousePosition.X
    
                    If Me.DropDownStyle = ComboBoxStyle.Simple Then
                        yPos = LocalMousePosition.Y - (Me.ItemHeight + 10)
                    Else
                        yPos = LocalMousePosition.Y - Me.Size.Height - 1
                    End If
    
                    ' save our y position which we need to ensure the cursor is
                    ' inside the drop down list for updating purposes
                    Dim oldYPos As Integer = yPos
    
                    ' get the 0-based index of where the cursor is on screen
                    ' as if it were inside the listbox
                    While yPos >= Me.ItemHeight
                        yPos -= Me.ItemHeight
                        onScreenIndex += 1
                    End While
    
                    'if (yPos < 0) { onScreenIndex = -1; }
                    Dim si As New ScrollInfoStruct()
                    si.fMask = SIF_ALL
                    si.cbSize = Marshal.SizeOf(si)
                    ' msg.LParam holds the hWnd to the drop down list that appears
                    Dim getScrollInfoResult As Integer = 0
                    getScrollInfoResult = GetScrollInfo(msg.LParam, SB_VERT, si)
    
                    ' k returns 0 on error, so if there is no error add the current
                    ' track position of the scrollbar to our index
                    If getScrollInfoResult > 0 Then
                        onScreenIndex += si.nTrackPos
    
                        If Me.DropDownStyle = ComboBoxStyle.Simple Then
                            simpleOffset = si.nTrackPos
                        End If
                    End If
    
                    ' Add our offset modifier if we're a simple combobox since we don't
                    ' continuously receive scrollbar information in this mode.
                    ' Then make sure the item we're previewing is actually on screen.
                    If Me.DropDownStyle = ComboBoxStyle.Simple Then
                        onScreenIndex += simpleOffset
                        If onScreenIndex > ((Me.DropDownHeight / Me.ItemHeight) + simpleOffset) Then
                            onScreenIndex = ((Me.DropDownHeight / Me.ItemHeight) + simpleOffset - 1)
                        End If
                    End If
    
                    ' Check we're actually inside the drop down window that appears and 
                    ' not just over its scrollbar before we actually try to update anything
                    ' then if we are raise the Hover event for this comboBox
                    If Not (xPos > Me.Width - SCROLLBAR_WIDTH OrElse xPos < 1 OrElse oldYPos < 0 OrElse ((oldYPos > Me.ItemHeight * Me.MaxDropDownItems) AndAlso Me.DropDownStyle <> ComboBoxStyle.Simple)) Then
                        Dim e As New HoverEventArgs()
                        e.itemIndex = If((onScreenIndex > Me.Items.Count - 1), Me.Items.Count - 1, onScreenIndex)
                        OnHover(e)
                        ' if scrollPos doesn't equal the nPos from our ScrollInfoStruct then
                        ' the mousewheel was most likely used to scroll the drop down list
                        ' while the mouse was inside it - this means we have to manually
                        ' tell the drop down to repaint itself to update where it is hovering
                        ' still posible to "outscroll" this method but it works better than
                        ' without it present
                        If scrollPos <> si.nPos Then
                            Cursor.Position = New Point(Cursor.Position.X + xFactor, Cursor.Position.Y)
                            xFactor = -xFactor
                        End If
                    End If
                    scrollPos = si.nPos
                End If
                ' Pass on our message
                MyBase.WndProc(msg)
            End Sub
        End Class
    
        ''' <summary>
        ''' Class that contains data for the hover event 
        ''' </summary>
        Public Class HoverEventArgs
            Inherits EventArgs
            Private _itemIndex As Integer = 0
            Public Property itemIndex() As Integer
                Get
                    Return _itemIndex
                End Get
                Set(value As Integer)
                    _itemIndex = value
                End Set
            End Property
        End Class
    
        ''' <summary>
        ''' Delegate declaration 
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        Public Delegate Sub HoverEventHandler(sender As Object, e As HoverEventArgs)
    
    End Namespace
    

    No logro resolver d´´onde radica el error. Si alguien puede resolverlo... Gracias de nuevo


    Miguel Ángel Muñoz

    miércoles, 31 de agosto de 2016 7:15
  • Concretamente es aqu´´i donde se produce el error:

            Public Event Hover As HoverEventHandler
    
            Protected Overridable Sub OnHover(e As HoverEventArgs)
                Dim handler As HoverEventHandler = Hover
                ' Invokes the delegates. 
                RaiseEvent handler(Me, e)
            End Sub
    

    El texto del error es: " 'Public Event Hover(sender As Object, e As HoverEventArgs)' es un evento y no se puede llamar directamente. Utilice la instrucción RaiseEvent para provocar un evento."


    Miguel Ángel Muñoz

    miércoles, 31 de agosto de 2016 8:31
  • Y a continuaci´´on

                ' Invokes the delegates. 
                RaiseEvent handler(Me, e)
    
    l´´ogicamente, se da otro error.

    Miguel Ángel Muñoz

    miércoles, 31 de agosto de 2016 8:34
  • "Miguel Ángel Muñoz" escribió:

    > Concretamente es aqu´´i donde se produce el error:
    >
    >        Public Event Hover As HoverEventHandler
    >
    >        Protected Overridable Sub OnHover(e As HoverEventArgs)
    >            Dim handler As HoverEventHandler = Hover
    >            ' Invokes the delegates.
    >            RaiseEvent handler(Me, e)
    >        End Sub
    >
    > El texto del error es: " 'Public Event Hover(sender As Object, e As HoverEventArgs)'
    > es un evento y no se puede llamar directamente. Utilice la instrucción RaiseEvent
    > para provocar un evento."

    Hola, Miguel Ángel:

    Sustituye el método OnHover por éste otro para desencadenar simplemente el evento Hover:

            Protected Overridable Sub OnHover(e As HoverEventArgs)
                RaiseEvent Hover(Me, e)
            End Sub

    Ten en cuenta que a éste método solamente lo llama la siguiente línea de código existente en el método WndProc:

            Dim e As New HoverEventArgs()
            e.itemIndex = If((onScreenIndex > Me.Items.Count - 1), Me.Items.Count - 1, onScreenIndex)
            OnHover(e)

    Por tanto, al método OnHover le está pasando una instancia de la clase HoverEventArgs válida, que es la que tienes que incluir en la instrucción RaiseEvent para desencadenar el evento Hover.

    Y en el formulario que contiene un control del tipo [Custom].MyComboBox, instalarías el controlador para el evento Hover:

        Private Sub MyComboBox1_Hover(sender As Object, e As HoverEventArgs) Handles MyComboBox1.Hover
    
            Dim cb As Custom.MyComboBox = DirectCast(sender, Custom.MyComboBox)
    
            Label1.Text = String.Format("Item {0} = {1}", e.itemIndex.ToString(), cb.Items(e.itemIndex))
    
        End Sub
    

    Por cierto, si tienes la instrucción Option Strict activada, que es lo recomendable, busca la siguiente línea que aparece en negrita en el método WndProc:

        If Me.DropDownStyle = ComboBoxStyle.Simple Then
            onScreenIndex += simpleOffset
            If (onScreenIndex > ((Me.DropDownHeight / Me.ItemHeight) + simpleOffset)) Then
                onScreenIndex = ((Me.DropDownHeight / Me.ItemHeight) + simpleOffset - 1)
            End If
        End If

    Y la sustituyes por la siguiente:

        onScreenIndex = CInt(((Me.DropDownHeight / Me.ItemHeight) + simpleOffset - 1))

    Un saludo


    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, 31 de agosto de 2016 18:55
    Moderador
  • Gracias, Enrique. Mis disculpas por no haber respondido pero he estaba bastante atareado ayer.

    Tal como indicas, yo mismo pude resolverlo haciendo pruebas según el texto del mensaje de error. Es lo que tiene de ser autodidacta, ya que hay muchas cosas que desconozco.

    Si tengo tiempo, hoy mismo voy a probar lo que propones. A ver qué tal.

    Y de nuevo, gracias a ambos por vuestra ayuda. Un saludo.


    Miguel Ángel Muñoz

    viernes, 2 de septiembre de 2016 6:23