Aracılığıyla paylaş


İzlenecek yol: 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ızda, kodun tamamen yeniden yazmak yerine wpf uygulamanızda en az bir kısmını yeniden kullanmak daha etkili olabilir. WPF, BIR WPF sayfasında Win32 penceresi barındırmak için basit bir mekanizma sağlar.

Bu konu, Win32 liste kutusu denetimini barındıran WPF Örneğinde Win32 ListBox Denetimi Barındırma adlı bir uygulamada size yol gösterir. Bu genel yordam herhangi bir Win32 penceresini barındırmak için genişletilebilir.

Gereksinimler

Bu konu başlığında hem WPF hem de Windows API programlama hakkında temel bir bilgi olduğu varsayılır. WPF programlamaya temel bir giriş için bkz Başlangıç. Windows API programlamaya giriş için, özellikle Charles Petzold'un Windows Programlaması başta olmak üzere konuyla ilgili sayısız kitaplardan herhangi birine bakın.

Bu konuya eşlik eden örnek C# dilinde uygulandığından, Windows API'sine erişmek için Platform Çağırma Hizmetleri'ni (PInvoke) kullanır. PInvoke hakkında bazı bilgiler yararlı olabilir ancak gerekli değildir.

Uyarı

Bu konu, ilişkili örnekten bir dizi kod örneği içerir. Ancak okunabilirlik için örnek kodun tamamını içermez. WPF Örneğinde Win32 ListBox Denetimi Barındırma bölümünden kodun tamamını alabilir veya görüntüleyebilirsiniz.

Temel Yordam

Bu bölümde, WPF sayfasında Win32 penceresi barındırmaya yönelik temel yordam özetlenmiştir. Kalan bölümlerde her adımın ayrıntılarına göz atabilirsiniz.

Temel barındırma yordamı:

  1. Pencereyi barındırmak için bir WPF sayfası uygulayın. Bir teknik, barındırılan pencere için sayfanın bir bölümünü ayırmak üzere bir öğe oluşturmaktır Border .

  2. öğesinden HwndHostdevralan denetimi barındırmak için bir sınıf uygulayın.

  3. Bu sınıfta, sınıf üyesini HwndHostBuildWindowCoregeçersiz kılın.

  4. Barındırılan pencereyi WPF sayfasını içeren pencerenin alt öğesi olarak oluşturun. Her ne kadar geleneksel WPF programlamasında HWND'nin açıkça kullanılmasına gerek olmasa da, barındırma sayfası bir pencere tutamağı (HWND) olan bir penceredir. Yöntemin hwndParent parametresi aracılığıyla BuildWindowCore sayfasının HWND'sini alırsınız. Barındırılan pencere bu HWND'nin alt öğesi olarak oluşturulmalıdır.

  5. Konak penceresini oluşturduktan sonra barındırılan pencerenin HWND değerini döndürebilirsiniz. Bir veya daha fazla Win32 denetimi barındırmak istiyorsanız, genellikle HWND'nin alt öğesi olarak bir konak penceresi oluşturur ve denetimleri bu konak penceresinin alt öğeleri yaparsınız. Denetimleri bir geçici konak penceresinde sarmalamak, WPF sayfanızın denetimlerden bildirim almasını basit bir şekilde sağlar. Bu çözüm, HWND sınırındaki bildirimlerle ilgili belirli Win32 sorunlarını ele alır.

  6. Çocuk kontrollerden gelen bildirimler gibi seçilmiş iletileri ana pencereye gönderildiğinde işleyin. Bunu yapmanın iki yolu vardır.

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

    • WPF'nin iletileri işlemesini tercih ediyorsanız, kod arkasındaki HwndHost sınıfı MessageHook olayını işleyin. Bu olay, barındırılan pencere tarafından alınan her ileti için gerçekleşir. Bu seçeneği belirlerseniz, yine de WndProc öğesini geçersiz kılmanız gerekir; ancak yalnızca asgari düzeyde bir uygulamaya ihtiyacınız vardır.

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

  8. Arka plan kod dosyanızda, denetim barındırma sınıfının bir örneğini oluşturun ve bu örneği, pencereyi barındırmak için tasarlanan Border öğesinin alt öğesi yapın.

  9. Microsoft Windows iletileri göndererek ve denetimler tarafından gönderilen bildirimler gibi alt pencerelerindeki iletileri işleyerek barındırılan pencereyle iletişim kurun.

Sayfa Düzenini Uygulama

ListBox Denetimini barındıran WPF sayfasının düzeni iki bölgeden oluşur. Sayfanın sol tarafında, Win32 denetimini işlemenizi sağlayan bir kullanıcı arabirimi (UI) sağlayan çeşitli WPF denetimleri bulunur. Sayfanın sağ üst köşesinde barındırılan ListBox Denetimi için kare bir bölge vardır.

Bu düzeni uygulamak için kod oldukça basittir. Kök öğesi, iki alt öğe içeren bir DockPanel öğesidir. birincisi ListBox Denetimini barındıran bir Border öğedir. Sayfanın sağ üst köşesindeki 200x200 karesini kaplar. İkincisi, StackPanel bilgileri görüntüleyen ve kullanıma sunulan birlikte çalışma özelliklerini ayarlayarak ListBox Denetimini işlemenize olanak sağlayan bir WPF denetimleri kümesi içeren bir öğedir. StackPanel öğesinin alt öğesi olan her bir öğe için, kullanılan çeşitli öğelere dair ayrıntılar ve bu öğelerin ne oldukları veya ne yaptıkları hakkında bilgi almak için başvuru materyaline bakın. Bunlar aşağıdaki örnek kodda listelenmiştir ancak burada açıklanmayacaktır (temel birlikte çalışma modeli bunlardan hiçbirini gerektirmez; örneğe etkileşim eklemek için sağlanmıştı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 Denetimini Barındıran Sınıfı Uygula

Bu örneğin temeli, denetimi ControlHost.cs barındıran sınıftır. HwndHost öğesinden devralır. Oluşturucu, ListBox denetimini barındıran Border öğesinin yüksekliği ve genişliğine karşılık gelen iki parametre, yükseklik ve genişlik, alır. Bu değerler daha sonra denetimin boyutunun öğesiyle Border eşleştiğinden emin olmak için 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

Ayrıca bir dizi sabit vardır. Bu sabitler büyük ölçüde Winuser.h'den alınır ve Win32 işlevlerini çağırırken geleneksel adları kullanmanıza 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 Penceresi Oluşturmak için BuildWindowCore'u Geçersiz Kılma

Sayfa tarafından barındırılacak Win32 penceresini oluşturmak ve pencere ile sayfa arasında bağlantı kurmak için bu yöntemi geçersiz kılarsınız. 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 öğesi olarak oluşturulur.

Bu yaklaşımın nedeni, denetimden bildirim alma işlemini basitleştirmektir. sınıfı, HwndHost barındırdığınız pencereye gönderilen iletileri işlemenize olanak tanır. Bir Win32 denetimini doğrudan barındırdıysanız, denetimin iç ileti döngüsüne gönderilen iletileri alırsınız. Denetimi görüntüleyebilir ve ileti 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şim kurduğunu algılamanın hiçbir yolunun olmadığı anlamına gelir. Bunun yerine bir ana pencere oluşturun ve denetimi bu pencerenin alt öğesi olarak tanımlayın. Bu, ana pencereye yönelik iletileri, kontroller tarafından gönderilen bildirimler de dahil olmak üzere işlemenizi sağlar. Kolaylık olması için, ana pencere kontrol için basit bir sarmalayıcıdan biraz fazlası olduğundan, paket bir ListBox kontrolü olarak adlandırılır.

Ana Pencere ve ListBox Kontrolünü Oluşturma

PInvoke kullanarak bir pencere sınıfı oluşturup kaydederek ve benzeri işlemler yaparak denetim için bir ana bilgisayar penceresi oluşturabilirsiniz. Ancak, çok daha basit bir yaklaşım, önceden tanımlanmış "statik" pencere sınıfıyla 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'si, ana bilgisayar sayfasının denetime ileti göndermek için kullanabilmesi için salt okunur bir özellik aracılığıyla kullanıma sunulur.

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

ListBox denetimi, konak penceresinin alt öğesi olarak oluşturulur. Her iki pencerelerin yüksekliği ve genişliği, yukarıda açıklanan oluşturucuya geçirilen değerlere ayarlanır. Bu, konak penceresinin ve denetiminin boyutunun sayfadaki ayrılmış alanla aynı olmasını sağlar. Pencereler oluşturulduktan sonra örnek, konak penceresinin HWND'sini içeren bir HandleRef 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'u Uygula

BuildWindowCore elemanına ek olarak, WndProc ve DestroyWindowCore yöntemlerini HwndHost'te geçersiz kılmalısınız. Bu örnekte, denetimin iletileri MessageHook işleyici tarafından ele alındığından, WndProc ve DestroyWindowCore uygulamaları minimaldir. durumunda, iletinin WndProcişlenmediğini belirtmek için handled olarak ayarlayın false ve 0 döndürür. DestroyWindowCore için sadece pencereyi yok edin.

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 yeni bir örneğini ControlHost oluşturursunuz. Denetimi (ControlHostElement) içeren kenarlık öğesinin yüksekliğini ve genişliğini oluşturucuya ControlHost geçirin. Bu, ListBox'ın doğru boyutlandırılmasını sağlar. Ardından, nesnesini konağın özelliğine atayarak ControlHost denetimi sayfada barındırabilirsinizChild.Border

Örnek, denetimden ileti almak için MessageHook olayına ControlHost üzerinde bir işleyici ekler. Bu olay, barındırılan pencereye gönderilen her ileti için oluşturulur. Bu durumda, bunlar denetimden gelen bildirimler de dahil olmak üzere gerçek ListBox denetimini sarmalayan pencereye gönderilen iletilerdir. Örnek, denetimden bilgi almak ve içeriğini değiştirmek için SendMessage'ı çağırır. Sayfanın denetimle nasıl iletişim kurulduğuna ilişkin ayrıntılar sonraki bölümde açıklanmıştır.

Uyarı

SendMessage için iki PInvoke bildirimi olduğuna dikkat edin. Biri bir dize geçirmek için parametresini wParam , diğeri de tamsayı geçirmek için parametresini kullandığından bu gereklidir. Verilerin doğru şekilde sıralandığından emin olmak için her imza için ayrı bir bildirime ihtiyacınız vardır.

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 ile Sayfa Arasında İletişim Gerçekleştirme

Kontrolü Windows mesajları göndererek manipüle edersiniz. Denetim, kullanıcı konak penceresine bildirim göndererek etkileşime geçtiğinde size bildirir. WPF'de Win32 ListBox Denetimi Barındırma örneği, bunun nasıl çalıştığına ilişkin çeşitli örnekler sağlayan bir kullanıcı arabirimi içerir:

  • Listeye bir öğe ekleyin.

  • Seçili öğeyi listeden silme

  • Seçili durumdaki öğenin metnini görüntüleyin.

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

Kullanıcı, geleneksel bir Win32 uygulaması için olduğu gibi, liste kutusunda bir öğeyi tıklayarak da seçebilir. Kullanıcı bir öğeyi seçip ekleyerek veya ekleme yoluyla liste kutusunun durumunu her değiştirdiğinde, görüntülenen veriler güncellenir.

Öğeleri eklemek için liste kutusuna bir LB_ADDSTRING ileti gönderin. Öğeleri silmek için, geçerli seçimin dizinini almak üzere LB_GETCURSEL ve ardından öğeyi silmek için LB_DELETESTRING gönderin. Örnek, ayrıca LB_GETCOUNT öğesini gönderir ve döndürülen değeri kullanarak öğe sayısını gösteren ekranı günceller. Bu iki örnek SendMessage de ö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 öğeyi seçtiğinde veya seçimini değiştirdiğinde, denetim bir ileti göndererek WM_COMMANDkonak penceresine MessageHook bildirim gönderir ve bu da sayfa için olayı tetikler. İşleyici, ana pencerenin ana pencere işleviyle aynı bilgileri alır. Ayrıca boole değerine handledbaşvuru geçirir. Mesajı işlediğinizi ve başka bir işleme gerek olmadığını belirtmek için handled'yı true olarak ayarlayın.

WM_COMMAND çeşitli nedenlerle gönderilir, bu nedenle işlemek istediğiniz bir olay olup olmadığını belirlemek için bildirim kimliğini incelemeniz gerekir. Kimlik, parametrenin yüksek kelimesinde wParam yer alır. Kimliği ayıklamak için örnek, bit düzeyinde işleçler kullanır. Kullanıcı seçimini yaptıysa veya değiştirdiyse, kimlik LBN_SELCHANGE olacaktır.

LBN_SELCHANGE Alındığında, örnek denetime bir LB_GETCURSEL ileti göndererek seçili öğenin dizinini alır. Metni almak için önce bir StringBuilderoluşturursunuz. Ardından denetime bir LB_GETTEXT ileti gönderirsiniz. Boş StringBuilder nesneyi wParam parametre olarak geçirin. SendMessage geri döndüğünde, StringBuilder seçili öğenin metnini içerir. Bu SendMessage kullanımı için başka bir PInvoke bildirimi gerekir.

Son olarak, iletinin işlendiğini belirtmek için handled'yu true olarak ayarlayın.

Ayrıca bakınız