Adım adım kılavuz: WPF'de Win32 Denetimi Barındırma

Windows Presentation Foundation (WPF), uygulama oluşturmak için zengin bir ortam sağlar. Ancak, Win32 koduna önemli bir yatırım yaptığnız zaman, kodu tamamen yeniden yazmak yerine wpF uygulamanıza en azından bir kodu yeniden kullanmak daha etkili olabilir. WPF, WPF sayfasında Win32 penceresi barındırmak için basit bir mekanizma sağlar.

Bu konu, WPF Örneğinde Win32 ListBoxDenetimi Barındıran ve Win32 liste kutusu denetimi barındıran bir uygulamada size yol sağlar. Bu genel yordam, herhangi bir Win32 penceresini barındırmak için genişletilmiştir.

Gereksinimler

Bu konu başlığında, hem WPF hem de api programlama ile ilgili Windows bilgisi varsaymaktadır. WPF programlamaya temel bir giriş için bkz. Başlarken. Api programlamaya Windows için, özellikle Charles Petzold'un programlama Windows konu kitaplarına bakın.

Bu konuya eşlik ediyor olan örnek C# ile uygulamaya alınarak Platform Çağırma Hizmetleri'nin (PInvoke) Windows kullanılır. PInvoke hakkında biraz bilgi sahibi olmak faydalıdır ancak gerekli değildir.

Not

Bu konu, ilişkili örnekten bir dizi kod örneği içerir. Ancak okunabilirlik için örnek kodun tamamını içermemektedir. WPF Örneğinde Win32 ListBox Denetimi Barındırma'dan tam kodu edinebilirsiniz veya görüntüebilirsiniz.

Temel Yordam

Bu bölümde, WPF sayfasında Win32 penceresi barındırmak için temel yordam özetlemektedir. Kalan bölümler her adımın ayrıntılarını içerir.

Temel barındırma yordamı şu şekildedir:

  1. Pencereyi barındırmak için bir WPF sayfası uygulama. Tekniklerden biri, sayfanın Border bir bölümünü barındırılan pencere için rezervasyon yapmak için bir öğe oluşturmaktır.

  2. 'den devralınan denetimi barındırmak için bir sınıf HwndHost uygulama.

  3. Bu sınıfta, sınıf üyesini HwndHost geçersiz BuildWindowCore kılın.

  4. Barındırılan pencereyi WPF sayfasını içeren pencerenin alt adı olarak oluşturun. Geleneksel WPF programlamanın bunu açıkça kullanması gerekse de, barındırma sayfası tanıtıcısı (HWND) olan bir penceredir. HWND sayfasını yönteminin hwndParent parametresi aracılığıyla BuildWindowCore alırsınız. Barındırılan pencere bu HWND'nin alt adı olarak oluşturulsun.

  5. Konak penceresini oluşturduktan sonra, barındırılan pencerenin HWND'lerini geri dönebilirsiniz. Bir veya daha fazla Win32 denetimi barındırmak için genellikle HWND'nin alt adı olarak bir konak penceresi oluşturmanız ve denetimleri bu konak penceresinin alt altlarını oluşturmanız gerekir. Denetimleri bir konak penceresinde sarmalama, WPF sayfanıza denetimlerden bildirim almak için basit bir yol sağlar ve bu da HWND sınırındaki bildirimlerle ilgili bazı Win32 sorunlarını ele alır.

  6. Alt denetimlerden gelen bildirimler gibi konak penceresine gönderilen seçili iletileri işle. Bunu yapmanın iki yolu vardır.

    • Barındırma sınıfınıza iletileri işlemeyi tercih ediyorsanız sınıfının WndProc yöntemini geçersiz HwndHost kılın.

    • WPF'nin iletileri işlemesi tercih ederseniz, arka HwndHost arkasındaki MessageHook kodda sınıf olayı işle. Bu olay, barındırılan pencere tarafından alınan her ileti için gerçekleşir. Bu seçeneği seçerseniz, yine de geçersiz WndProc kılmalı, ancak yalnızca en az uygulama gerekir.

  7. ve DestroyWindowCore yöntemlerini WndProc geçersiz HwndHost kılın. Sözleşmeyi karşılamak için bu yöntemleri geçersiz HwndHost kılmanız gerekir, ancak yalnızca en az uygulama sağlamanız yeterli olabilir.

  8. Arka arkasındaki kod dosyanızda, denetim barındırma sınıfının bir örneğini oluşturun ve pencereyi barındırmak için Border amaçlanan öğenin alt öğesi olarak oluşturun.

  9. Barındırılan pencereyle iletişim kurmak için Microsoft Windows ve denetimler tarafından gönderilen bildirimler gibi alt pencerelerinden iletileri işle.

Sayfa Düzenini Uygulama

ListBox Denetimi barındıran WPF sayfasının düzeni iki bölgeden oluşur. Sayfanın sol tarafında, Win32 denetiminde işlemeye olanak sağlayan bir kullanıcı arabirimi (UI) sağlayan birkaç WPF denetimi barındırabilirsiniz. Sayfanın sağ üst köşesinde barındırılan ListBox Denetimi için kare bir bölge vardır.

Bu düzeni uygulayan kod oldukça basittir. Kök öğe, iki DockPanel alt öğeye sahip olan bir öğesidir. birincisi Border ListBox Denetimi'nin barındır olduğu bir öğedir. Sayfanın sağ üst köşesinde 200x200 kare yer almaktadır. İkincisi, bilgileri görüntülemeye ve ortaya çıkan birlikte çalışma özelliklerini ayarerek ListBox Denetimi'ne göz alamamalarına olanak sağlayan bir dizi WPF denetimi içeren StackPanel bir öğedir. alt öğeleri olan öğelerin her biri için, bu öğelerin ne olduğu veya ne yaptığıyla ilgili ayrıntılar için kullanılan çeşitli öğelere yönelik başvuru malzemelerine bakın, bunlar aşağıdaki örnek kodda listelenmiştir ancak burada açıklanmaz (temel birlikte çalışma modeli bunlardan herhangi birini gerektirmez, örneğine biraz etkileşim eklemek için StackPanel sağlanır).

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="WPF_Hosting_Win32_Control.HostWindow"
  Name="mainWindow"
  Loaded="On_UIReady">

  <DockPanel Background="LightGreen">
    <Border Name="ControlHostElement"
    Width="200"
    Height="200"
    HorizontalAlignment="Right"
    VerticalAlignment="Top"
    BorderBrush="LightGray"
    BorderThickness="3"
    DockPanel.Dock="Right"/>
    <StackPanel>
      <Label HorizontalAlignment="Center"
        Margin="0,10,0,0"
        FontSize="14"
        FontWeight="Bold">Control the Control</Label>
      <TextBlock Margin="10,10,10,10" >Selected Text: <TextBlock  Name="selectedText"/></TextBlock>
      <TextBlock Margin="10,10,10,10" >Number of Items: <TextBlock  Name="numItems"/></TextBlock>
  
      <Line X1="0" X2="200"
        Stroke="LightYellow"
        StrokeThickness="2"
        HorizontalAlignment="Center"
        Margin="0,20,0,0"/>
  
      <Label HorizontalAlignment="Center"
        Margin="10,10,10,10">Append an Item to the List</Label>
      <StackPanel Orientation="Horizontal">
        <Label HorizontalAlignment="Left"
          Margin="10,10,10,10">Item Text</Label>
        <TextBox HorizontalAlignment="Left"
          Name="txtAppend"
          Width="200"
          Margin="10,10,10,10"></TextBox>
      </StackPanel>
  
      <Button HorizontalAlignment="Left"
        Click="AppendText"
        Width="75"
        Margin="10,10,10,10">Append</Button>

      <Line X1="0" X2="200"
        Stroke="LightYellow"
        StrokeThickness="2"
        HorizontalAlignment="Center"
        Margin="0,20,0,0"/>
  
      <Label HorizontalAlignment="Center"
        Margin="10,10,10,10">Delete the Selected Item</Label>
  
      <Button Click="DeleteText"
        Width="125"
        Margin="10,10,10,10"
        HorizontalAlignment="Left">Delete</Button>
    </StackPanel>
  </DockPanel>
</Window>  

Microsoft Win32 Denetimi Barındırmak için Sınıf Uygulama

Bu örneğin çekirdeği, ControlHost.cs denetimi barındıran sınıftır. 'den HwndHost devralıyor. Oluşturucu, ListBox denetimi barındıran öğenin yüksekliğine ve genişliğine karşılık gelen height ve width Border olmak için iki parametre alır. Bu değerler daha sonra denetimin boyutunun öğeyle eş olduğundan emin olmak için Border kullanılır.

public class ControlHost : HwndHost
{
  IntPtr hwndControl;
  IntPtr hwndHost;
  int hostHeight, hostWidth;

  public ControlHost(double height, double width)
  {
    hostHeight = (int)height;
    hostWidth = (int)width;
  }
Public Class ControlHost
    Inherits HwndHost
  Private hwndControl As IntPtr
  Private hwndHost As IntPtr
  Private hostHeight, hostWidth As Integer

  Public Sub New(ByVal height As Double, ByVal width As Double)
          hostHeight = CInt(height)
          hostWidth = CInt(width)
  End Sub

Bir dizi sabit de vardır. Bu sabitler büyük ölçüde Winuser.h'den alınır ve Win32 işlevlerini çağırarak geleneksel adlar kullanmana olanak sağlar.

internal const int
  WS_CHILD = 0x40000000,
  WS_VISIBLE = 0x10000000,
  LBS_NOTIFY = 0x00000001,
  HOST_ID = 0x00000002,
  LISTBOX_ID = 0x00000001,
  WS_VSCROLL = 0x00200000,
  WS_BORDER = 0x00800000;
Friend Const WS_CHILD As Integer = &H40000000, WS_VISIBLE As Integer = &H10000000, LBS_NOTIFY As Integer = &H00000001, HOST_ID As Integer = &H00000002, LISTBOX_ID As Integer = &H00000001, WS_VSCROLL As Integer = &H00200000, WS_BORDER As Integer = &H00800000

Microsoft Win32 Penceresini Oluşturmak için BuildWindowCore'u Geçersiz Kılma

Bu yöntemi geçersiz kılarak sayfada barındıracak Win32 penceresini oluşturun ve pencere ile sayfa arasında bağlantı oluşturun. Bu örnek bir ListBox Denetimi barındırmayı içerdiği için iki pencere oluşturulur. Birincisi, WPF sayfası tarafından barındırılan penceredir. ListBox Denetimi bu pencerenin alt bir alt listesi olarak oluşturulur.

Bu yaklaşımın nedeni denetimden bildirim alma sürecini basitleştirmektir. sınıfı, HwndHost barındırmış olduğu pencereye gönderilen iletileri işlemeye olanak sağlar. Win32 denetimlerini doğrudan barındırarak denetimin iç ileti döngüsüne gönderilen iletileri alırsınız. Denetimi görüntüp iletiler gönderebilirsiniz, ancak denetimin üst penceresine gönderdiği bildirimleri almazsınız. Bu, diğer şeylerin yanında, kullanıcının denetimle ne zaman etkileşime geldiğini algılamanın bir yolunun olmadığını ifade eder. Bunun yerine, bir konak penceresi oluşturun ve denetimi bu pencerenin alt adı olarak kullanın. Bu, denetim tarafından gönderilen bildirimler de dahil olmak üzere konak penceresi için iletileri işlemeye olanak sağlar. Kolaylık sağlamak için, konak penceresi denetim için basit bir sarmalayıcıdan biraz daha fazlası olduğu için paket ListBox denetimi olarak adlandırılır.

Konak Penceresi ve ListBox Denetimi Oluşturma

PInvoke'u kullanarak bir pencere sınıfı oluşturarak ve kaydederek denetim için bir konak penceresi oluşturabilirsiniz. Ancak, çok daha basit bir yaklaşım, önceden tanımlanmış "statik" pencere sınıfına sahip bir pencere oluşturmaktır. Bu, denetimden bildirim almak için ihtiyacınız olan pencere yordamını sağlar ve en az kodlama gerektirir.

Denetimin HWND'i salt okunur bir özellik aracılığıyla açığa çıkar, böylece konak sayfası denetime ileti göndermek için bu özelliği kullanabilir.

public IntPtr hwndListBox
{
  get { return hwndControl; }
}
Public ReadOnly Property hwndListBox() As IntPtr
  Get
      Return hwndControl
  End Get
End Property

ListBox denetimi, konak penceresinin alt adı olarak oluşturulur. Her iki pencerenin yüksekliği ve genişliği, yukarıda ele alınarak oluşturucuya geçirilen değerlere ayarlanır. Bu, konak penceresinin ve denetimin boyutunun sayfada ayrılmış alanla aynı olması sağlar. Pencereler oluşturulduktan sonra örnek, konak HandleRef penceresinin HWND'sini içeren bir nesne döndürür.

protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
  hwndControl = IntPtr.Zero;
  hwndHost = IntPtr.Zero;

  hwndHost = CreateWindowEx(0, "static", "",
                            WS_CHILD | WS_VISIBLE,
                            0, 0,
                            hostWidth, hostHeight,
                            hwndParent.Handle,
                            (IntPtr)HOST_ID,
                            IntPtr.Zero,
                            0);

  hwndControl = CreateWindowEx(0, "listbox", "",
                                WS_CHILD | WS_VISIBLE | LBS_NOTIFY
                                  | WS_VSCROLL | WS_BORDER,
                                0, 0,
                                hostWidth, hostHeight,
                                hwndHost,
                                (IntPtr) LISTBOX_ID,
                                IntPtr.Zero,
                                0);

  return new HandleRef(this, hwndHost);
}
Protected Overrides Function BuildWindowCore(ByVal hwndParent As HandleRef) As HandleRef
  hwndControl = IntPtr.Zero
  hwndHost = IntPtr.Zero

  hwndHost = CreateWindowEx(0, "static", "", WS_CHILD Or WS_VISIBLE, 0, 0, hostWidth, hostHeight, hwndParent.Handle, New IntPtr(HOST_ID), IntPtr.Zero, 0)

  hwndControl = CreateWindowEx(0, "listbox", "", WS_CHILD Or WS_VISIBLE Or LBS_NOTIFY Or WS_VSCROLL Or WS_BORDER, 0, 0, hostWidth, hostHeight, hwndHost, New IntPtr(LISTBOX_ID), IntPtr.Zero, 0)

  Return New HandleRef(Me, hwndHost)
End Function
//PInvoke declarations
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateWindowEx(int dwExStyle,
                                              string lpszClassName,
                                              string lpszWindowName,
                                              int style,
                                              int x, int y,
                                              int width, int height,
                                              IntPtr hwndParent,
                                              IntPtr hMenu,
                                              IntPtr hInst,
                                              [MarshalAs(UnmanagedType.AsAny)] object pvParam);
'PInvoke declarations
<DllImport("user32.dll", EntryPoint := "CreateWindowEx", CharSet := CharSet.Unicode)>
Friend Shared Function CreateWindowEx(ByVal dwExStyle As Integer, ByVal lpszClassName As String, ByVal lpszWindowName As String, ByVal style As Integer, ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer, ByVal hwndParent As IntPtr, ByVal hMenu As IntPtr, ByVal hInst As IntPtr, <MarshalAs(UnmanagedType.AsAny)> ByVal pvParam As Object) As IntPtr
End Function

DestroyWindow ve WndProc uygulama

'ye ek BuildWindowCore olarak, ve yöntemlerini WndProc de geçersiz DestroyWindowCore kılmalı. HwndHost Bu örnekte, denetimin iletileri işleyici tarafından işleyicinin uygulanması MessageHook ve en WndProc düşük DestroyWindowCore düzeydedir. durumunda, iletinin iş olmadığını belirtmek için olarak WndProchandled ayarlayın ve false 0'a geri döner. için DestroyWindowCore pencereyi yok etmek için tek yapmanız gereken.

protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
  handled = false;
  return IntPtr.Zero;
}

protected override void DestroyWindowCore(HandleRef hwnd)
{
  DestroyWindow(hwnd.Handle);
}
Protected Overrides Function WndProc(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
  handled = False
  Return IntPtr.Zero
End Function

Protected Overrides Sub DestroyWindowCore(ByVal hwnd As HandleRef)
  DestroyWindow(hwnd.Handle)
End Sub
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
internal static extern bool DestroyWindow(IntPtr hwnd);
<DllImport("user32.dll", EntryPoint := "DestroyWindow", CharSet := CharSet.Unicode)>
Friend Shared Function DestroyWindow(ByVal hwnd As IntPtr) As Boolean
End Function

Denetimi Sayfada Barındırma

Denetimi sayfada barındırmak için önce sınıfının yeni bir örneğini oluşturmanız ControlHost gerekir. Denetimi içeren sınır öğesinin yüksekliğini ve genişliğini ( ControlHostElement ) oluşturucuya ControlHost iletir. Bu, ListBox'ın doğru boyutlandırnmalarını sağlar. Ardından, nesnesini konak özelliğine ataarak ControlHost denetimi Child sayfada Border barındırabilirsiniz.

Örnek, denetiminden ileti almak MessageHook için ControlHost olayına bir işleyici iliştirer. Bu olay, barındırılan pencereye gönderilen her ileti için ortaya çıkar. Bu durumda bunlar, denetimden gelen bildirimler de dahil olmak üzere gerçek ListBox denetimi sarmalayıcı pencereye gönderilen iletilerdir. Örnek, denetimden bilgi almak ve içeriğini değiştirmek için SendMessage'ı arar. Sayfanın denetimle nasıl iletişim kuracakları sonraki bölümde ele alınmıştır.

Not

SendMessage için iki PInvoke bildirimi vardır. Biri dizeyi geçmek için parametresini, diğeri ise tamsayıyı wParam geçmek için kullandığı için bu gereklidir. Verilerin doğru sıra olduğundan emin olmak için her imza için ayrı bir bildirim gerekir.

public partial class HostWindow : Window
{
int selectedItem;
IntPtr hwndListBox;
ControlHost listControl;
Application app;
Window myWindow;
int itemCount;

private void On_UIReady(object sender, EventArgs e)
{
  app = System.Windows.Application.Current;
  myWindow = app.MainWindow;
  myWindow.SizeToContent = SizeToContent.WidthAndHeight;
  listControl = new ControlHost(ControlHostElement.ActualHeight, ControlHostElement.ActualWidth);
  ControlHostElement.Child = listControl;
  listControl.MessageHook += new HwndSourceHook(ControlMsgFilter);
  hwndListBox = listControl.hwndListBox;
  for (int i = 0; i < 15; i++) //populate listbox
  {
    string itemText = "Item" + i.ToString();
    SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, itemText);
  }
  itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
  numItems.Text = "" +  itemCount.ToString();
}
Partial Public Class HostWindow
    Inherits Window
    Private selectedItem As Integer
    Private hwndListBox As IntPtr
    Private listControl As ControlHost
    Private app As Application
    Private myWindow As Window
    Private itemCount As Integer

    Private Sub On_UIReady(ByVal sender As Object, ByVal e As EventArgs)
        app = System.Windows.Application.Current
        myWindow = app.MainWindow
        myWindow.SizeToContent = SizeToContent.WidthAndHeight
        listControl = New ControlHost(ControlHostElement.ActualHeight, ControlHostElement.ActualWidth)
        ControlHostElement.Child = listControl
        AddHandler listControl.MessageHook, AddressOf ControlMsgFilter
        hwndListBox = listControl.hwndListBox
        For i As Integer = 0 To 14 'populate listbox
            Dim itemText As String = "Item" & i.ToString()
            SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, itemText)
        Next i
        itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero)
        numItems.Text = "" & itemCount.ToString()
    End Sub

private IntPtr ControlMsgFilter(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
  int textLength;

  handled = false;
  if (msg == WM_COMMAND)
  {
    switch ((uint)wParam.ToInt32() >> 16 & 0xFFFF) //extract the HIWORD
    {
      case LBN_SELCHANGE : //Get the item text and display it
        selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero);
        textLength = SendMessage(listControl.hwndListBox, LB_GETTEXTLEN, IntPtr.Zero, IntPtr.Zero);
        StringBuilder itemText = new StringBuilder();
        SendMessage(hwndListBox, LB_GETTEXT, selectedItem, itemText);
        selectedText.Text = itemText.ToString();
        handled = true;
        break;
    }
  }
  return IntPtr.Zero;
}
internal const int
  LBN_SELCHANGE = 0x00000001,
  WM_COMMAND = 0x00000111,
  LB_GETCURSEL = 0x00000188,
  LB_GETTEXTLEN = 0x0000018A,
  LB_ADDSTRING = 0x00000180,
  LB_GETTEXT = 0x00000189,
  LB_DELETESTRING = 0x00000182,
  LB_GETCOUNT = 0x0000018B;

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern int SendMessage(IntPtr hwnd,
                                       int msg,
                                       IntPtr wParam,
                                       IntPtr lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern int SendMessage(IntPtr hwnd,
                                       int msg,
                                       int wParam,
                                       [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern IntPtr SendMessage(IntPtr hwnd,
                                          int msg,
                                          IntPtr wParam,
                                          String lParam);

Private Function ControlMsgFilter(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
    Dim textLength As Integer

    handled = False
    If msg = WM_COMMAND Then
        Select Case CUInt(wParam.ToInt32()) >> 16 And &HFFFF 'extract the HIWORD
            Case LBN_SELCHANGE 'Get the item text and display it
                selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero)
                textLength = SendMessage(listControl.hwndListBox, LB_GETTEXTLEN, IntPtr.Zero, IntPtr.Zero)
                Dim itemText As New StringBuilder()
                SendMessage(hwndListBox, LB_GETTEXT, selectedItem, itemText)
                selectedText.Text = itemText.ToString()
                handled = True
        End Select
    End If
    Return IntPtr.Zero
End Function
Friend Const LBN_SELCHANGE As Integer = &H1, WM_COMMAND As Integer = &H111, LB_GETCURSEL As Integer = &H188, LB_GETTEXTLEN As Integer = &H18A, LB_ADDSTRING As Integer = &H180, LB_GETTEXT As Integer = &H189, LB_DELETESTRING As Integer = &H182, LB_GETCOUNT As Integer = &H18B

<DllImport("user32.dll", EntryPoint:="SendMessage", CharSet:=CharSet.Unicode)>
Friend Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function

<DllImport("user32.dll", EntryPoint:="SendMessage", CharSet:=CharSet.Unicode)>
Friend Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lParam As StringBuilder) As Integer
End Function

<DllImport("user32.dll", EntryPoint:="SendMessage", CharSet:=CharSet.Unicode)>
Friend Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As String) As IntPtr
End Function

Denetim ve sayfa arasındaki Iletişimi Uygula

Windows iletileri göndererek denetimi düzenleyebilirsiniz. Denetim, ana bilgisayar penceresine bildirim göndererek Kullanıcı onunla etkileşime geçtiğinde size bildirir. WPF örneğinde Win32 ListBox denetimini barındırma , bunun nasıl çalıştığına dair birkaç örnek sağlayan bir kullanıcı arabirimi içerir:

  • Listeye bir öğe ekleyin.

  • Seçili öğeyi listeden Sil

  • Şu anda seçili olan öğenin metnini görüntüleyin.

  • Listedeki öğelerin sayısını görüntüleyin.

Kullanıcı aynı zamanda, Ayrıca, geleneksel bir Win32 uygulaması gibi, bu öğeye tıklayarak liste kutusunda bir öğe seçebilir. Görünen veriler, Kullanıcı bir öğe seçerek, ekleyerek veya ekleyerek liste kutusunun durumunu her değiştirdiğinde güncellenir.

Öğeleri eklemek için liste kutusuna bir iletigönderin. Öğeleri silmek için Gönder ' LB_GETCURSEL e, geçerli seçimin dizinini alın ve sonra LB_DELETESTRING öğeyi silin. Örnek ayrıca LB_GETCOUNT , öğelerin sayısını gösteren görünümü güncelleştirmek için döndürülen değeri de gönderir ve kullanır. Bu örneklerin her ikisi de SendMessage önceki bölümde açıklanan PInvoke bildirimlerinden birini kullanır.

private void AppendText(object sender, EventArgs args)
{
  if (!string.IsNullOrEmpty(txtAppend.Text))
  {
    SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, txtAppend.Text);
  }
  itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
  numItems.Text = "" + itemCount.ToString();
}
private void DeleteText(object sender, EventArgs args)
{
  selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero);
  if (selectedItem != -1) //check for selected item
  {
    SendMessage(hwndListBox, LB_DELETESTRING, (IntPtr)selectedItem, IntPtr.Zero);
  }
  itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
  numItems.Text = "" + itemCount.ToString();
}
Private Sub AppendText(ByVal sender As Object, ByVal args As EventArgs)
    If txtAppend.Text <> String.Empty Then
        SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, txtAppend.Text)
    End If
    itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero)
    numItems.Text = "" & itemCount.ToString()
End Sub
Private Sub DeleteText(ByVal sender As Object, ByVal args As EventArgs)
    selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero)
    If selectedItem <> -1 Then 'check for selected item
        SendMessage(hwndListBox, LB_DELETESTRING, New IntPtr(selectedItem), IntPtr.Zero)
    End If
    itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero)
    numItems.Text = "" & itemCount.ToString()
End Sub

Kullanıcı bir öğe seçtiğinde veya seçimlerini değiştirdiğinde, denetim konak penceresine bir iletigöndererek bildirir ve bu da MessageHook sayfanın olayını oluşturur. İşleyici, ana bilgisayar penceresinin ana pencere yordamıyla aynı bilgileri alır. Ayrıca, bir Boolean değerine bir başvuru geçirir handled . handledtrue ' İ, iletiyi işlediğinin ve başka bir işleme gerek olmadığını belirtecek şekilde ayarlayın.

WM_COMMAND çeşitli nedenlerle gönderilir, bu nedenle, işlemek istediğiniz bir olay olup olmadığını öğrenmek için bildirim KIMLIĞINI incelemeniz gerekir. KIMLIĞI, parametresinin üst sözcüğünde bulunur wParam . Örnek, KIMLIĞI ayıklamak için bit düzeyinde işleçler kullanır. Kullanıcı, seçimini yapmış veya değiştirmiştir, KIMLIK olur LBN_SELCHANGE .

LBN_SELCHANGEAlındığında, örnek, denetim bir LBN_SELCHANGEgöndererek seçili öğenin dizinini alır. Metni almak için önce bir oluşturun StringBuilder . Ardından, denetimi bir iletigönderirsiniz. Boş StringBuilder nesneyi parametre olarak geçirin wParam . SendMessageDöndüğünde, StringBuilder Seçili öğenin metnini içerir. Bu kullanımı, SendMessage henüz başka bir PInvoke bildirimi gerektirir.

Son olarak, handledtrue iletinin işlendiğini göstermek için olarak ayarlayın.

Ayrıca bkz.