Condividi tramite


Tutorial: Hosting di oggetti visivi in un'applicazione Win32

Windows Presentation Foundation (WPF) offre un ambiente avanzato per la creazione di applicazioni. Tuttavia, quando si ha un notevole investimento nel codice Win32, potrebbe essere più efficace aggiungere funzionalità WPF all'applicazione invece di riscrivere il codice. Per fornire supporto per i sottosistemi grafici Win32 e WPF usati simultaneamente in un'applicazione, WPF fornisce un meccanismo per l'hosting di oggetti in una finestra Win32.

Questa esercitazione descrive come scrivere un'applicazione di esempio, Hit Test con l'esempio di interoperabilità Win32, che ospita oggetti visivi WPF in una finestra Win32.

Requisiti

Questa esercitazione presuppone una familiarità di base con la programmazione WPF e Win32. Per un'introduzione di base alla programmazione WPF, vedere Guida: Prima applicazione desktop WPF. Per un'introduzione alla programmazione Win32, vedi uno dei numerosi libri sul tema, in particolare Programmazione di Windows di Charles Petzold.

Annotazioni

Questa esercitazione include diversi esempi di codice dell'esempio associato. Tuttavia, per la leggibilità, non include il codice di esempio completo. Per il codice di esempio completo, vedere Hit Test con l'esempio di interoperabilità Win32.

Creazione della finestra Host Win32

La chiave per ospitare oggetti WPF in una finestra Win32 è la classe HwndSource. Questa classe avvolge gli oggetti WPF in una finestra Win32, consentendo di incorporarli nell'interfaccia utente (UI) come finestra figlia.

Nell'esempio seguente viene illustrato il codice per la creazione dell'oggetto HwndSource come finestra del contenitore Win32 per gli oggetti visivi. Per impostare lo stile della finestra, la posizione e altri parametri per la finestra Win32, usare l'oggetto 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;
}
' 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

Annotazioni

Il valore della proprietà ExtendedWindowStyle non può essere impostato su WS_EX_TRANSPARENT. Ciò significa che la finestra Win32 host non può essere trasparente. Per questo motivo, il colore di sfondo della finestra Win32 host viene impostato sullo stesso colore di sfondo della finestra padre.

Aggiunta di oggetti visivi alla finestra Host Win32

Dopo aver creato una finestra contenitore Win32 host per gli oggetti visivi, è possibile aggiungervi oggetti visivi. È necessario assicurarsi che qualsiasi trasformazione degli oggetti visivi, ad esempio le animazioni, non si estenda oltre i limiti del rettangolo di delimitazione della finestra Win32 host.

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

Annotazioni

La proprietà RootVisual dell'oggetto HwndSource viene impostata sul primo oggetto visivo aggiunto alla finestra Win32 host. L'oggetto visivo radice definisce il nodo più in alto della struttura ad albero degli oggetti visivi. Tutti gli oggetti visivi seguenti aggiunti alla finestra host di Win32 vengono aggiunti come oggetti figli.

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);
    }
}
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

Implementazione del filtro messaggi Win32

La finestra host Win32 per gli oggetti visivi richiede una procedura di filtro dei messaggi della finestra per gestire i messaggi inviati alla finestra dalla coda dell'applicazione. La procedura della finestra riceve messaggi dal sistema Win32. Possono trattarsi di messaggi di input o messaggi di gestione delle finestre. Facoltativamente, è possibile gestire un messaggio nella routine della finestra o passare il messaggio al sistema per l'elaborazione predefinita.

L'oggetto HwndSource che hai definito come padre per gli oggetti visivi deve fare riferimento alla procedura di filtro dei messaggi della finestra che fornisci. Quando si crea l'oggetto HwndSource, impostare la proprietà HwndSourceHook per fare riferimento alla routine della finestra.

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

Nell'esempio seguente viene illustrato il codice per la gestione dei messaggi di rilascio del pulsante sinistro e destro del mouse. Il valore della coordinata della posizione di clic del mouse è contenuto nel valore del parametro lParam.

// 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;
}
' 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

Elaborazione dei messaggi Win32

Il codice nell'esempio seguente mostra come viene eseguito un hit test sulla gerarchia degli oggetti visivi contenuti nella finestra Win32 dell'host. È possibile identificare se un punto si trova all'interno della geometria di un oggetto visivo usando il metodo HitTest per specificare l'oggetto visivo radice e il valore della coordinata su cui eseguire il 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 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();
    }
}
' 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

Per altre informazioni sull'hit testing sugli oggetti visivi, vedere Hit Testing in Visual Layer.

Vedere anche