Bagikan melalui


Tutorial: Menghosting Objek Visual dalam Aplikasi Win32

Windows Presentation Foundation (WPF) menyediakan lingkungan yang kaya untuk membuat aplikasi. Namun, ketika Anda memiliki investasi besar dalam kode Win32, mungkin lebih efektif untuk menambahkan fungsionalitas WPF ke aplikasi Anda daripada menulis ulang kode Anda. Untuk memberikan dukungan untuk subsistem grafis Win32 dan WPF yang digunakan secara bersamaan dalam aplikasi, WPF menyediakan mekanisme untuk menghosting objek di jendela Win32.

Tutorial ini menjelaskan cara menulis aplikasi sampel, Hit Test dengan Win32 Interoperation Sample, yang menghosting objek visual WPF di jendela Win32.

Persyaratan

Tutorial ini mengasumsikan keakraban dasar dengan pemrograman WPF dan Win32. Untuk pengenalan dasar pemrograman WPF, lihat Panduan: Aplikasi desktop WPF pertama saya. Untuk pengantar pemrograman Win32, lihat salah satu dari banyak buku tentang subjek, khususnya Pemrograman Windows oleh Charles Petzold.

Catatan

Tutorial ini mencakup sejumlah contoh kode dari sampel terkait. Namun, untuk keterbacaan, kode sampel lengkap tidak disertakan. Untuk kode sampel lengkap, lihat Uji Hit dengan Sampel Interoperabilitas Win32.

Membuat Jendela Win32 Host

Kunci untuk menghosting objek WPF di jendela Win32 adalah kelasnya HwndSource . Kelas ini membungkus objek WPF di jendela Win32, memungkinkan mereka untuk dimasukkan ke dalam antarmuka pengguna (UI) Anda sebagai jendela anak.

Contoh berikut menunjukkan kode untuk membuat HwndSource objek sebagai jendela kontainer Win32 untuk objek visual. Untuk mengatur gaya jendela, posisi, dan parameter lainnya untuk jendela Win32, gunakan HwndSourceParameters objek .

// 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

Catatan

Nilai ExtendedWindowStyle properti tidak dapat diatur ke WS_EX_TRANSPARENT. Ini berarti bahwa jendela Win32 host tidak dapat transparan. Untuk alasan ini, warna latar belakang jendela Win32 host diatur ke warna latar belakang yang sama dengan jendela induknya.

Menambahkan Objek Visual ke Jendela Host Win32

Setelah Anda membuat jendela kontainer Win32 host untuk objek visual, Anda dapat menambahkan objek visual ke dalamnya. Anda akan ingin memastikan bahwa transformasi objek visual apa pun, seperti animasi, tidak melampaui batas persegi panjang pembatas jendela Win32 host.

Contoh berikut menunjukkan kode untuk membuat HwndSource objek dan menambahkan objek visual ke dalamnya.

Catatan

Properti RootVisualHwndSource objek diatur ke objek visual pertama yang ditambahkan ke jendela Win32 host. Objek visual akar mendefinisikan simpul paling atas dari pohon objek visual. Objek visual berikutnya yang ditambahkan ke jendela Win32 host ditambahkan sebagai objek turunan.

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

Menerapkan Filter Pesan Win32

Jendela Win32 host untuk objek visual memerlukan prosedur filter pesan jendela untuk menangani pesan yang dikirim ke jendela dari antrean aplikasi. Prosedur jendela menerima pesan dari sistem Win32. Ini mungkin pesan input atau pesan manajemen jendela. Anda dapat secara opsional menangani pesan dalam prosedur jendela Anda atau meneruskan pesan ke sistem untuk pemrosesan default.

Objek HwndSource yang Anda tentukan sebagai induk untuk objek visual harus mereferensikan prosedur filter pesan jendela yang Anda sediakan. Saat Anda membuat HwndSource objek, atur HwndSourceHook properti untuk mereferensikan prosedur jendela.

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

Contoh berikut menunjukkan kode untuk menangani pesan tombol mouse kiri dan kanan ke atas. Nilai koordinat posisi hit mouse terkandung dalam nilai lParam parameter .

// 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

Memproses Pesan Win32

Kode dalam contoh berikut menunjukkan bagaimana pengujian hit dilakukan terhadap hierarki objek visual yang terkandung di jendela Win32 host. Anda dapat mengidentifikasi apakah titik berada dalam geometri objek visual, dengan menggunakan HitTest metode untuk menentukan objek visual akar dan nilai koordinat yang akan diuji. Dalam hal ini, objek visual akar adalah nilai RootVisual properti HwndSource objek.

// 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

Untuk informasi selengkapnya tentang pengujian hit terhadap objek visual, lihat Pengujian Hit di Lapisan Visual.

Baca juga