Condividi tramite


Esercitazione: hosting di oggetti visivi in un'applicazione Win32

Windows Presentation Foundation (WPF) fornisce un ambiente funzionale per la creazione di applicazioni. Tuttavia, se si utilizza una grande quantità di codice Win32, può essere più efficace aggiungere funzionalità WPF all'applicazione anziché riscrivere il codice. Per fornire un supporto per i sottosistemi grafici di Win32 e di WPF utilizzati contemporaneamente in un'applicazione, WPF fornisce un meccanismo per ospitare oggetti in una finestra Win32.

In questa esercitazione viene illustrato come scrivere un'applicazione di esempio, disponibile in Esempio di hit test con interoperatività Win32 (la pagina potrebbe essere in inglese), che ospita oggetti visivi WPF in una finestra Win32.

Nel presente argomento sono contenute le seguenti sezioni.

  • Requisiti
  • Creazione di una finestra Win32 host
  • Aggiunta di oggetti visivi alla finestra Win32 host
  • Implementazione del filtro messaggi Win32
  • Elaborazione dei messaggi Win32
  • Argomenti correlati

Requisiti

Per questa esercitazione si presuppone una conoscenza di base della programmazione WPF e Win32. Per un'introduzione alla programmazione WPF, vedere Procedura dettagliata: introduzione a WPF. Per un'introduzione alla programmazione Win32, vedere uno qualsiasi dei numerosi manuali sull'argomento, in particolare Programmare Windows di Charles Petzold.

NotaNota

In questa esercitazione sono inclusi diversi esempi di codice relativi all'esempio associato.Tuttavia, per una questione di leggibilità, il codice di esempio completo non è compreso.Per il codice di esempio completo, vedere Esempio di hit test con interoperatività Win32.

Creazione di una finestra Win32 host

La chiave per ospitare oggetti WPF in una finestra Win32 è la classe HwndSource. Questa classe esegue il wrapping degli oggetti WPF in una finestra Win32, consentendo di incorporarli nell'user interface (UI) come finestra figlio.

Nell'esempio seguente viene mostrato il codice per la creazione dell'oggetto HwndSource come finestra contenitore Win32 per gli oggetti visivi. Per impostare lo stile, la posizione e altri parametri della finestra Win32, utilizzare l'oggetto HwndSourceParameters.

' Constant values from the "winuser.h" header file.
Friend Const WS_CHILD As Integer = &H40000000, WS_VISIBLE As Integer = &H10000000

Friend Shared Sub CreateHostHwnd(ByVal parentHwnd As IntPtr)
    ' Set up the parameters for the host hwnd.
    Dim parameters As New HwndSourceParameters("Visual Hit Test", _width, _height)
    parameters.WindowStyle = WS_VISIBLE Or WS_CHILD
    parameters.SetPosition(0, 24)
    parameters.ParentWindow = parentHwnd
    parameters.HwndSourceHook = New HwndSourceHook(AddressOf 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
End Sub
// 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;
}
NotaNota

Il valore della proprietà ExtendedWindowStyle non può essere impostato su WS_EX_TRANSPARENT.Di conseguenza, la finestra Win32 host non può essere trasparentee per questo motivo il colore di sfondo della finestra Win32 host sarà impostato sullo stesso colore di sfondo della finestra padre.

Aggiunta di oggetti visivi alla finestra Win32 host

Una volta creata una finestra contenitore Win32 host per gli oggetti visivi, è possibile aggiungere tali oggetti alla finestra. Sarà necessario che qualsiasi trasformazione degli oggetti visivi, ad esempio le animazioni, non si estendano oltre i limiti del rettangolo di delimitazione della finestra Win32 host.

Nell'esempio seguente viene mostrato il codice per la creazione dell'oggetto HwndSource e l'aggiunta di oggetti visivi a tale oggetto.

NotaNota

La proprietà RootVisual dell'oggetto HwndSource è impostata sul primo oggetto visivo aggiunto alla finestra Win32 host.L'oggetto visivo radice definisce il nodo di primo livello della struttura ad albero di oggetti visivi.Eventuali oggetti visivi aggiunti successivamente alla finestra Win32 host vengono inseriti come oggetti figlio.

Public Shared Sub CreateShape(ByVal parentHwnd As IntPtr)
    ' Create an instance of the shape.
    Dim myShape As New MyShape()

    ' Determine whether the host container window has been created.
    If myHwndSource Is Nothing Then
        ' 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.
        CType(myHwndSource.RootVisual, ContainerVisual).Children.Add(myShape)
    End If
End Sub
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);
    }
}

Implementazione del filtro messaggi Win32

La finestra Win32 host per gli oggetti visivi richiede una procedura del filtro messaggi della finestra per gestire i messaggi inviati alla finestra dalla coda dell'applicazione. La routine della finestra riceve i messaggi dal sistema Win32. Può trattarsi di messaggi di input o di messaggi di gestione della finestra. È possibile facoltativamente gestire un messaggio nella routine della finestra oppure passarlo al sistema per l'elaborazione predefinita.

L'oggetto HwndSource definito come elemento padre per gli oggetti visivi deve fare riferimento alla routine del filtro messaggi della finestra fornita. Al momento della creazione dell'oggetto HwndSource, impostare la proprietà HwndSourceHook in modo da fare riferimento alla routine della finestra.

parameters.HwndSourceHook = New HwndSourceHook(AddressOf ApplicationMessageFilter)
parameters.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);

Nell'esempio seguente viene mostrato il codice per la gestione dei messaggi di rilascio dei pulsanti sinistro e destro del mouse. Il valore di coordinate della posizione rilevata del mouse è contenuto nel valore del parametro lParam.

' Constant values from the "winuser.h" header file.
Friend Const WM_LBUTTONUP As Integer = &H202, WM_RBUTTONUP As Integer = &H205

Friend Shared Function ApplicationMessageFilter(ByVal hwnd As IntPtr, ByVal message As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
    ' Handle messages passed to the visual.
    Select Case message
        ' Handle the left and right mouse button up messages.
        Case WM_LBUTTONUP, WM_RBUTTONUP
            Dim pt As New System.Windows.Point()
            pt.X = CUInt(lParam) And CUInt(&HFFFF) ' LOWORD = x
            pt.Y = CUInt(lParam) >> 16 ' HIWORD = y
            MyShape.OnHitTest(pt, message)
    End Select

    Return IntPtr.Zero
End Function
// 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;
}

Elaborazione dei messaggi Win32

Nel codice dell'esempio seguente viene illustrata l'esecuzione di un hit test sulla gerarchia di oggetti visivi contenuta nella finestra Win32 host. È possibile individuare se un punto è compreso all'interno della geometria di un oggetto visivo utilizzando il metodo HitTest per specificare l'oggetto visivo radice e il valore delle coordinate in base a cui eseguire l'hit test. In questo caso, l'oggetto visivo radice è il valore della proprietà RootVisual dell'oggetto HwndSource.

        ' Constant values from the "winuser.h" header file.
        Public Const WM_LBUTTONUP As Integer = &H0202, WM_RBUTTONUP As Integer = &H0205

        ' Respond to WM_LBUTTONUP or WM_RBUTTONUP messages by determining which visual object was clicked.
        Public Shared Sub OnHitTest(ByVal pt As System.Windows.Point, ByVal msg As Integer)
            ' 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 Then
                MyWindow.changeColor = True
            End If
            If msg = WM_RBUTTONUP Then
                MyWindow.changeColor = False
            End If

            ' Set up a callback to receive the hit test results enumeration.
            VisualTreeHelper.HitTest(MyWindow.myHwndSource.RootVisual, Nothing, New HitTestResultCallback(AddressOf CircleHitTestResult), New PointHitTestParameters(pt))

            ' Perform actions on the hit test results list.
            If hitResultsList.Count > 0 Then
                ProcessHitTestResultsList()
            End If
        End Sub
// 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();
    }
}

Per ulteriori informazioni sull'hit testing su oggetti visivi, vedere Hit testing a livello visivo.

Vedere anche

Riferimenti

HwndSource

Concetti

Hit testing a livello visivo

Altre risorse

Esempio di hit test con interoperatività Win32