Crear subclases de controles con un procedimiento de ventana administrado
Actualización: noviembre 2007
.NET Compact Framework dispone de una función que permite que el código nativo llame al código administrado mediante un delegado de devolución de llamada. Mediante la creación de subclases de un control administrado para que reciba una devolución de llamada de su control nativo correspondiente, se pueden crear controles con una funcionalidad que no está disponible de forma directa en .NET Compact Framework.
Éste es un tema avanzado para desarrolladores expertos en programación para Windows y en la creación de subclases de controles. Para crear una subclase de un control, debe conocer los detalles internos del control nativo y cómo asigna la funcionalidad que desea proporcionar en la extensión del control administrado. Necesitará conocer qué mensajes de Windows hay que supervisar y qué funciones nativas de Windows Embedded CE hay que invocar para proporcionar la funcionalidad deseada.
Este tema describe la creación de subclases de controles TreeView y Button y los temas siguientes proporcionan ejemplos de código e instrucciones para generar las aplicaciones.
Tema Cómo |
Explica |
---|---|
Cómo: Crear subclases de un control TreeView mediante devoluciones de llamada nativas |
Crear subclases del control TreeView para crear una implementación del evento NodeMouseClick. .NET Compact Framework no admite este método directamente porque debe limitar su tamaño para los recursos restringidos. |
Cómo: Crear subclases de un botón mediante devoluciones de llamada nativas |
Crear subclases del control Button para mostrar un relleno de degradado multicolor. Tenga en cuenta que este botón se incluye sobre todo para mostrar cómo utilizar la creación de subclases y devoluciones de llamada. Para obtener información sobre una manera más fácil de crear un botón de relleno de degradado, vea Cómo: Mostrar un relleno de degradado. |
Ambos programas de creación de subclases incluyen la clase WndProcHooker y una clase auxiliar de estructuras Win32 nativas, declaraciones de la invocación de la plataforma y un delegado WndProc. Para obtener información sobre listas de código, vea Cómo: Utilizar una clase para enlazar procedimientos de Windows y Cómo: Usar una clase auxiliar para las invocaciones de la plataforma.
Clase WndProcHooker
La clase WndProcHooker permite que un control nativo, o ventana, invoque una devolución de llamada al código administrado cuando dicho control recibe un determinado mensaje de Windows. Esto se consigue sustituyendo un procedimiento de ventana (WndProc) del control con un procedimiento de ventana genérico, WindowProc, que realiza una búsqueda para determinar si el control se encuentra en una lista de controles asociados a los métodos de devolución de llamada que se van a invocar. En ese caso, se considera que el control está enlazado.
Si el control está enlazado, WindowProc determina si el control está asignado para responder a un mensaje de Windows determinado. Éste es el mapa de mensajes, que asigna un mensaje de Windows a un delegado WndProcCallback que llama al método administrado que contiene la funcionalidad deseada. Si el mapa de mensajes contiene el mensaje, el delegado WndProcCallback invoca al código utilizando los parámetros de mensaje proporcionados a WindowProc.
Enlazar controles
El método HookWndProc asocia el identificador del control a un mapa de mensajes que lo va a utilizar el procedimiento de ventana genérico WindowProc. Este método se conoce como enlazar un control.
El método HookWndProc determina si ya se ha enlazado un control. En caso contrario, crea un objeto HookedProcInformation para ese control. Este objeto contiene una referencia al control y al mapa de mensajes. Si ya se ha creado el identificador del control, éste enlaza la ventana creando un puntero al procedimiento de ventana original de la ventana para una posterior restauración. Si no se ha creado el identificador, lo enlazará el método ctrl_HandleCreated que controla el evento HandleCreated.
A continuación, el método HookWndProc agrega el objeto HookedProcInformation a una de las dos colecciones de diccionarios genéricas:
El diccionario hwindDict, que contiene una lista global de todos los identificadores de ventana enlazados. La clave es un hwnd. Los controles cuyos identificadores se han creado entran en este diccionario. WindowProc evalúa los controles de este diccionario para cualquier mensaje asignado.
El diccionario ctlDict, que contiene controles cuyos identificadores no se han creado. Cuando se llama al método ctrl_HandleCreated, el control se mueve al diccionario hwndDict.
Eliminar enlaces en los controles
El método UnhookWndProc proporciona dos mecanismos para eliminar los enlaces de un control:
Quita un mensaje del mapa de mensajes para un control pero mantiene todavía el control en el diccionario hwndDict de ventanas enlazadas. Este método también restaura el procedimiento de la ventana original para el control utilizando un puntero contenido en el objeto HookedProcInformation.
Quita el control del diccionario hwndDict de controles enlazados y, o bien elimina su identificador y lo sitúa en el diccionario ctrlDict, o bien elimina completamente el control. Este método también restaura el procedimiento de la ventana original para el control utilizando un identificador contenido en el objeto HookedProcInformation.
Crear subclases en el control TreeView
La clase TreeViewBonus del programa de ejemplo, mostrada en Cómo: Crear subclases de un control TreeView mediante devoluciones de llamada nativas, amplía el control TreeView para incluir el evento NodeMouseClick, que no está directamente disponible en .NET Compact Framework.
El evento NodeMouseClick se obtiene agregando el mensaje WM_NOTIFY al mapa de mensajes para el control, realizado por la clase WndProcHooker. El método de devolución de llamadas administrado WM_Notify_Handler invoca a la función nativa GetMessagePos para obtener las coordenadas del cursor del mouse en el momento del envío de los mensajes Windows.
Tenga en cuenta que estas coordenadas están en relación con el área de cliente visible de la pantalla, no con el control TreeView. La clase TreeViewBonus convierte las coordenadas de la pantalla en coordenadas del cliente con el método PointToClient para el control. A continuación, estas coordenadas del cliente se envían con el mensaje TVM_HITTEST para determinar si se hizo clic en el objeto TreeViewBonus y dónde.
La clase TreeViewBonus contiene el código para obtener las coordenadas relativas al control mediante el mensaje de control TVM_HITTEST nativo.
Si el clic tiene lugar en uno de los nodos de vista de árbol, la estructura TVHITTESTINFO nativa contiene el identificador a ese nodo. El paso final es recorrer de forma recursiva los nodos TreeView administrados, que lo realiza el método FindTreeNodeFromHandle, para encontrar el identificador coincidente y producir el evento NodeMouseClick. La clase TreeNodeMouseClickEventArgs proporciona los datos siguientes:
El nodo en el que se hizo clic.
El botón en el que se hizo clic.
El número de clics, establecido en 1.
La coordenada x donde tuvo lugar el clic.
La coordenada y donde tuvo lugar el clic.
La clase TreeViewBonus enlaza el elemento primario del control de vista de árbol nativo a un procedimiento de ventana administrado, tal como lo ha realizado la clase WndProcHooker. Responde al evento OnParentChanged enlazando el control primario, admitiendo por tanto la posibilidad de que TreeView se haya desplazado a un nuevo elemento primario, como desde el Form y hacia un Panel.
Crear subclases en el control Button
Las clases GradientFilledButton y GradientFill mostradas en Cómo: Crear subclases de un botón mediante devoluciones de llamada nativas amplían el control Button para mostrar un relleno de degradado entre dos colores. El objetivo de este programa es mostrar la creación de subclases. Sin embargo, una forma más fácil de mostrar un relleno de degradado en un botón consiste en crear un control personalizado derivado de Control, como se describe en Cómo: Mostrar un relleno de degradado.
El constructor para la clase GradientFilledButton crea instancias de la clase WndProcHooker para asignar mensajes de Windows a las devoluciones de llamada administradas. Estos métodos de devolución de llamada dibujan el botón en el estado apropiado en función del mensaje de Windows y del estado de la propiedad Capture para el control. La tabla siguiente muestra los mensajes de Windows asignados y sus devoluciones de llamada correspondientes.
Mensaje de Windows |
Método y descripción de la devolución de llamada administrada |
---|---|
WM_KEYDOWN |
WM_KeyDown_Handler: vuelve a dibujar el botón en un estado presionado si se presiona la tecla BARRA ESPACIADORA o ENTRAR (o Acción). |
WM_KEYUP |
WM_KeyUp_Handler: vuelve a dibujar el botón en un estado no presionado y provoca el evento Click si la tecla presionada es la tecla BARRA ESPACIADORA o ENTRAR (Acción). |
WM_LBUTTONDOWN |
WM_LeftButtonDown_Hander: vuelve a dibujar el botón en un estado presionado y establece la propiedad Capture del mouse para el control en true. |
WM_LBUTTONUP |
WM_LButtonUp_Handler: vuelve a dibujar el botón en un estado sin presionar, provoca el evento MouseUp si el cursor se ha soltado dentro del área de cliente del control, y establece la propiedad Capture del mouse para el control en false. |
WM_MOUSEMOVE |
WM_MouseMove_Handler: vuelve a dibujar el botón si se ha hecho clic en él previamente y si la propiedad Capture es true. |
WM_PAINT |
WM_Paint_Handler: vuelve a dibujar el botón en el estado adecuado. |
Estos métodos de devolución de llamada administrados utilizan el método DrawButton para dibujar el botón en el estado adecuado. Este método tiene dos sobrecargas para dibujar el botón en una ventana, utilizado en este ejemplo, o en un objeto Graphics. Ambas sobrecargas toman un valor booleano que es true si se ha presionado el botón.
La clase GradientFilledButton utiliza la clase GradientFill para realizar las llamadas de la invocación de la plataforma al código nativo para realizar el relleno. La clase GradientFill proporciona las propiedades para establecer los colores de inicio y de fin y para especificar la dirección de relleno de izquierda a derecha o de arriba a abajo.
Vea también
Tareas
Cómo: Utilizar una clase para enlazar procedimientos de Windows
Cómo: Usar una clase auxiliar para las invocaciones de la plataforma
Cómo: Crear subclases de un control TreeView mediante devoluciones de llamada nativas
Cómo: Mostrar un relleno de degradado
Conceptos
.Temas "Cómo..." de .NET Compact Framework