Tutorial: Hospedar objetos visuales en una aplicación Win32

 

Publicado: junio de 2016

Windows Presentation Foundation (WPF) proporciona un entorno enriquecido para la creación de aplicaciones. Sin embargo, cuando ya se tiene una inversión sustancial en código de Entity with relative path '../Token/TLA%23tla_win32_md.md' can not be found, for source topic '{"project_id":"3fedad16-eaf1-41a6-8f96-0c1949c68f32","entity_id":"f0e1600c-3217-43d5-875d-1864fa7fe628","entity_type":"Article","locale":"es-ES"}'., puede ser más eficaz agregar la funcionalidad de WPF a la aplicación en lugar de volver a escribir el código. Para proporcionar la compatibilidad con los subsistemas de gráficos de Entity with relative path '../Token/TLA%23tla_win32_md.md' can not be found, for source topic '{"project_id":"3fedad16-eaf1-41a6-8f96-0c1949c68f32","entity_id":"f0e1600c-3217-43d5-875d-1864fa7fe628","entity_type":"Article","locale":"es-ES"}'. y WPF que se utilizan de manera simultánea en una aplicación, WPF proporciona un mecanismo para hospedar objetos en una ventana de Win32.

Este tutorial describe cómo escribir una aplicación de ejemplo, Hit Test with Win32 Interoperation Sample, que hospeda objetos visuales de WPF en una ventana Win32.

Entity with relative path '../Token/autoOutline_md.md' can not be found, for source topic '{"project_id":"3fedad16-eaf1-41a6-8f96-0c1949c68f32","entity_id":"f0e1600c-3217-43d5-875d-1864fa7fe628","entity_type":"Article","locale":"es-ES"}'.

En este tutorial se da por hecho que está familiarizado con la programación básica en WPF y Win32. Para obtener una introducción básica a la programación en WPF, vea Tutorial: Introducción a WPF. Para obtener una introducción a la programación en Win32, vea cualquiera de los numerosos libros sobre el tema, en particular Programming Windows escrito por Charles Petzold.

System_CAPS_ICON_note.jpg Nota

En este tutorial se incluyen varios ejemplos de código del ejemplo asociado. Sin embargo, para facilitar la legibilidad, no se incluye el código de ejemplo completo. Para obtener el ejemplo de código completo, vea Hit Test with Win32 Interoperation Sample.

La clave para hospedar objetos de WPF en una ventana de Win32 es la clase HwndSource. Esta clase ajusta los objetos de WPF en una ventana de Win32, con lo que permite incorporarlos a la interfaz de usuario (UI) como una ventana secundaria.

En el ejemplo siguiente se muestra el código utilizado para crear el objeto HwndSource como la ventana contenedora de Win32 para los objetos visuales. Para establecer el estilo, la posición y otros parámetros de la ventana de Win32 ventana, utilice el objeto HwndSourceParameters.

        // Constant values from the "winuser.h" header file.
        internal const int WS_CHILD = 0x40000000,
                           WS_VISIBLE = 0x10000000;

        internal static void CreateHostHwnd(IntPtr parentHwnd)
        {
            // Set up the parameters for the host hwnd.
            HwndSourceParameters parameters = new HwndSourceParameters("Visual Hit Test", _width, _height);
            parameters.WindowStyle = WS_VISIBLE | WS_CHILD;
            parameters.SetPosition(0, 24);
            parameters.ParentWindow = parentHwnd;
            parameters.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);

            // Create the host hwnd for the visuals.
            myHwndSource = new HwndSource(parameters);

            // Set the hwnd background color to the form's background color.
            myHwndSource.CompositionTarget.BackgroundColor = System.Windows.Media.Brushes.OldLace.Color;
        }

System_CAPS_ICON_note.jpg Nota

El valor de la propiedad ExtendedWindowStyle no se puede establecer en WS_EX_TRANSPARENT. Esto significa que la ventana host de Win32 no puede ser transparente. Por esta razón, el color de fondo de la ventana host de Win32 está establecido en el mismo color de fondo que su ventana primaria.

Una vez creada la ventana host de Win32 contenedora para los objetos visuales, puede agregarle los objetos visuales. Es conveniente asegurarse de que ninguna transformación de los objetos visuales, como las animaciones, se extienda más allá de los límites del rectángulo delimitador de la ventana host de Win32.

En el ejemplo siguiente se muestra el código utilizado para crear el objeto HwndSource y agregarle objetos visuales.

System_CAPS_ICON_note.jpg Nota

La propiedad RootVisual del objeto HwndSource se establece en el primer objeto visual agregado a la ventana host de Win32. El objeto visual raíz define el nodo de nivel superior del árbol de objetos visuales. Todos los objetos visuales subsiguientes se agregan a la ventana host de Win32 como objetos secundarios.

        public static void CreateShape(IntPtr parentHwnd)
        {
            // Create an instance of the shape.
            MyShape myShape = new MyShape();

            // Determine whether the host container window has been created.
            if (myHwndSource == null)
            {
                // Create the host container window for the visual objects.
                CreateHostHwnd(parentHwnd);

                // Associate the shape with the host container window.
                myHwndSource.RootVisual = myShape;
            }
            else
            {
                // Assign the shape as a child of the root visual.
                ((ContainerVisual)myHwndSource.RootVisual).Children.Add(myShape);
            }
        }

La ventana host de Win32 para los objetos visuales requiere un procedimiento de filtro de mensaje de ventana que administre los mensajes que se envían a la ventana desde la cola de la aplicación. El procedimiento de ventana recibe los mensajes del sistema de Win32. Éstos pueden ser mensajes de entrada o de administración de ventanas. Si lo desea, puede administrar un mensaje en el procedimiento de ventana o pasárselo al sistema para que se efectúe el procesamiento predeterminado.

El objeto HwndSource que definió como elemento primario para los objetos visuales debe hacer referencia al procedimiento de filtro de mensajes de ventana que proporcione. Al crear el objeto HwndSource, establezca la HwndSourceHook de tal forma que haga referencia al procedimiento de ventana.

            parameters.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);

En el ejemplo siguiente se muestra el código para administrar los mensajes que se emiten al soltar el botón primario y secundario del mouse. El valor del parámetro lParam contiene el valor de las coordenadas de la posición donde se hace clic con el mouse.

        // Constant values from the "winuser.h" header file.
        internal const int WM_LBUTTONUP = 0x0202,
                           WM_RBUTTONUP = 0x0205;

        internal static IntPtr ApplicationMessageFilter(
            IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            // Handle messages passed to the visual.
            switch (message)
            {
                // Handle the left and right mouse button up messages.
                case WM_LBUTTONUP:
                case WM_RBUTTONUP:
                    System.Windows.Point pt = new System.Windows.Point();
                    pt.X = (uint)lParam & (uint)0x0000ffff;  // LOWORD = x
                    pt.Y = (uint)lParam >> 16;               // HIWORD = y
                    MyShape.OnHitTest(pt, message);
                    break;
            }

            return IntPtr.Zero;
        }

En el código del ejemplo siguiente se muestra cómo se efectúa una prueba de posicionamiento con respecto a la jerarquía de objetos visuales contenida en la ventana host de Win32. Puede identificar si un punto está dentro de la geometría de un objeto visual utilizando el método HitTest para especificar el objeto visual raíz y el valor de las coordenadas con las que se comparará la prueba de posicionamiento. En este caso, el objeto visual raíz es el valor de la propiedad RootVisual del objeto HwndSource.

        // Constant values from the "winuser.h" header file.
        public const int WM_LBUTTONUP = 0x0202,
                         WM_RBUTTONUP = 0x0205;

        // Respond to WM_LBUTTONUP or WM_RBUTTONUP messages by determining which visual object was clicked.
        public static void OnHitTest(System.Windows.Point pt, int msg)
        {
            // Clear the contents of the list used for hit test results.
            hitResultsList.Clear();

            // Determine whether to change the color of the circle or to delete the shape.
            if (msg == WM_LBUTTONUP)
            {
                MyWindow.changeColor = true;
            }
            if (msg == WM_RBUTTONUP)
            {
                MyWindow.changeColor = false;
            }

            // Set up a callback to receive the hit test results enumeration.
            VisualTreeHelper.HitTest(MyWindow.myHwndSource.RootVisual,
                                     null,
                                     new HitTestResultCallback(CircleHitTestResult),
                                     new PointHitTestParameters(pt));

            // Perform actions on the hit test results list.
            if (hitResultsList.Count > 0)
            {
                ProcessHitTestResultsList();
            }
        }

Para obtener más información sobre las pruebas de posicionamiento con respecto a objetos visuales, vea Realizar pruebas de posicionamiento en la capa visual.

HwndSource
Hit Test with Win32 Interoperation Sample
Realizar pruebas de posicionamiento en la capa visual

Mostrar: