Návod: Hostování ovládacího prvku Win32 ve WPF

Windows Presentation Foundation (WPF) poskytuje bohaté prostředí pro vytváření aplikací. Pokud ale máte značné investice do kódu Win32, může být efektivnější znovu použít alespoň některý z těchto kódů v aplikaci WPF, nikoli jej úplně přepsat. WPF poskytuje jednoduchý mechanismus pro hostování okna Win32 na stránce WPF.

Toto téma vás provede aplikací hostováním ovládacího prvku Win32 ListBox v ukázce WPF, který je hostitelem ovládacího prvku seznamu Win32. Tento obecný postup lze rozšířit na hostování libovolného okna Win32.

Požadavky

V tomto tématu se předpokládá základní znalost programování rozhraní WPF i rozhraní API systému Windows. Základní úvod do programování WPF najdete v tématu Začínáme. Úvod do programování rozhraní API systému Windows naleznete v některé z mnoha knih na téma, zejména Programování Windows Charles Petzold.

Vzhledem k tomu, že ukázka, která doprovází toto téma, je implementována v jazyce C#, využívá službu PInvoke (Platform Invocation Services) pro přístup k rozhraní API systému Windows. Některé znalosti PInvoke jsou užitečné, ale nejsou nezbytné.

Poznámka:

Toto téma obsahuje řadu příkladů kódu z přidružené ukázky. Pro čitelnost ale neobsahuje úplný vzorový kód. Úplný kód můžete získat nebo zobrazit z hostování ovládacího prvku Win32 ListBox v ukázce WPF.

Základní postup

Tato část popisuje základní postup hostování okna Win32 na stránce WPF. Zbývající části procházejí podrobnostmi o jednotlivých krocích.

Základní postup hostování:

  1. Implementujte stránku WPF pro hostování okna. Jednou z technik je vytvoření Border prvku pro rezervaci oddílu stránky pro hostované okno.

  2. Implementujte třídu pro hostování ovládacího prvku, který dědí z HwndHost.

  3. V této třídě přepište HwndHost člen BuildWindowCoretřídy .

  4. Vytvořte hostované okno jako podřízené okno, které obsahuje stránku WPF. I když konvenční programování WPF nemusí explicitně používat, hostující stránka je okno s popisovačem (HWND). Obdržíte hwND stránky prostřednictvím hwndParent parametru BuildWindowCore metody. Hostované okno by mělo být vytvořeno jako podřízený tento HWND.

  5. Po vytvoření okna hostitele vraťte HWND hostovaného okna. Pokud chcete hostovat jeden nebo více ovládacích prvků Win32, obvykle vytvoříte jako podřízené okno hostitele HWND a nastavíte podřízené ovládací prvky tohoto okna hostitele. Zabalení ovládacích prvků do okna hostitele poskytuje jednoduchý způsob, jak na stránce WPF přijímat oznámení z ovládacích prvků, což se zabývá některými konkrétními problémy Win32 s oznámeními přes hranice HWND.

  6. Zpracování vybraných zpráv odeslaných do okna hostitele, například oznámení z podřízených ovládacích prvků Můžete to provést dvěma způsoby.

    • Pokud dáváte přednost zpracování zpráv ve třídě hostování, přepište WndProc metodu HwndHost třídy.

    • Pokud dáváte přednost tomu, aby WPF zpracovával zprávy, zpracujte HwndHost událost třídy MessageHook v kódu za sebou. K této události dochází pro každou zprávu přijatou hostovaným oknem. Pokud zvolíte tuto možnost, musíte přesto přepsat WndProc, ale potřebujete pouze minimální implementaci.

  7. DestroyWindowCore Přepsat a WndProc metody .HwndHost Tyto metody je nutné přepsat, aby vyhovovaly smlouvě HwndHost , ale možná budete muset poskytnout pouze minimální implementaci.

  8. V souboru kódu vytvořte instanci třídy hostování ovládacího prvku a nastavte ji jako podřízenou prvek Border , který je určen k hostování okna.

  9. Komunikujte s hostovaným oknem odesláním zpráv systému Microsoft Windows a zpracováním zpráv z podřízených oken, jako jsou oznámení odesílaná ovládacími prvky.

Implementace rozložení stránky

Rozložení stránky WPF, která je hostitelem ovládacího prvku ListBox, se skládá ze dvou oblastí. Na levé straně stránky je několik ovládacích prvků WPF, které poskytují uživatelské rozhraní, které vám umožní manipulovat s ovládacím prvku Win32. Pravý horní roh stránky má čtvercovou oblast pro hostovaný ovládací prvek ListBox.

Kód pro implementaci tohoto rozložení je poměrně jednoduchý. Kořenový prvek je DockPanel prvek, který má dva podřízené prvky. První je Border prvek, který je hostitelem ovládacího prvku ListBox. Zabírá čtvercový 200x200 v pravém horním rohu stránky. Druhý je StackPanel prvek, který obsahuje sadu ovládacích prvků WPF, které zobrazují informace a umožňují manipulovat s ovládacím prvkem ListBox nastavením vystavených vlastností vzájemné spolupráce. Pro každý z prvků, které jsou podřízeny StackPanel, viz referenční materiál pro různé prvky použité pro podrobnosti o tom, co tyto prvky jsou nebo co dělají, jsou uvedeny v níže uvedeném ukázkovém kódu, ale zde nebudou vysvětleny (základní interoperační model nevyžaduje žádné z nich, jsou k dispozici k přidání určité interaktivity k ukázce).

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

Implementace třídy pro hostování ovládacího prvku Microsoft Win32

Jádrem této ukázky je třída, která ve skutečnosti hostuje ovládací prvek ControlHost.cs. Dědí z HwndHost. Konstruktor přebírá dva parametry, výšku a šířku, které odpovídají výšce a šířce Border prvku, který je hostitelem ovládacího prvku ListBox. Tyto hodnoty se používají později k zajištění, že velikost ovládacího prvku odpovídá Border prvku.

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

K dispozici je také sada konstant. Tyto konstanty jsou z velké části převzaty z Winuser.h a umožňují používat konvenční názvy při volání funkcí Win32.

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

Přepsání BuildWindowCore pro vytvoření okna Microsoft Win32

Tuto metodu přepíšete tak, aby se vytvořilo okno Win32, které bude hostováno stránkou, a vytvořit propojení mezi oknem a stránkou. Vzhledem k tomu, že tato ukázka zahrnuje hostování ovládacího prvku ListBox, vytvoří se dvě okna. První je okno, které je ve skutečnosti hostováno stránkou WPF. Ovládací prvek ListBox se vytvoří jako podřízený prvek tohoto okna.

Důvodem tohoto přístupu je zjednodušení procesu přijímání oznámení z ovládacího prvku. Třída HwndHost umožňuje zpracovávat zprávy odeslané do okna, které je hostitelem. Pokud hostujete přímo ovládací prvek Win32, obdržíte zprávy odeslané do vnitřní smyčky zprávy ovládacího prvku. Ovládací prvek můžete zobrazit a odeslat zprávy, ale neobdržíte oznámení, která ovládací prvek odesílá do nadřazeného okna. To mimo jiné znamená, že nemáte žádný způsob, jak zjistit, kdy uživatel pracuje s ovládacím prvek. Místo toho vytvořte okno hostitele a nastavte ovládací prvek jako podřízený prvek tohoto okna. To vám umožní zpracovávat zprávy pro okno hostitele, včetně oznámení odeslaných ovládacím prvku. Pro usnadnění práce, protože okno hostitele je o něco víc než jednoduchý obálka pro ovládací prvek, balíček bude označován jako ListBox ovládacího prvku.

Vytvoření okna hostitele a ovládacího prvku ListBox

PInvoke můžete použít k vytvoření okna hostitele pro ovládací prvek vytvořením a registrací třídy okna atd. Mnohem jednodušší je však vytvořit okno s předdefinovanou třídou "statického" okna. Díky tomu máte postup okna, který potřebujete k příjmu oznámení z ovládacího prvku a vyžaduje minimální kódování.

HWND ovládacího prvku je vystaven prostřednictvím vlastnosti jen pro čtení, aby ji hostitelská stránka mohl použít k odesílání zpráv do ovládacího prvku.

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

Ovládací prvek ListBox je vytvořen jako podřízený okno hostitele. Výška a šířka obou oken jsou nastaveny na hodnoty předané konstruktoru, které jsou popsány výše. Tím se zajistí, že velikost okna hostitele a ovládacího prvku budou shodné s vyhrazenou oblastí na stránce. Po vytvoření oken vrátí HandleRef ukázka objekt, který obsahuje HWND okna hostitele.

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

Implementace DestroyWindow a WndProc

Kromě BuildWindowCore, musíte také přepsat WndProc a DestroyWindowCore metody HwndHost. V tomto příkladu se zprávy pro ovládací prvek zpracovávají obslužnou rutinou MessageHook , takže implementace WndProc a DestroyWindowCore je minimální. V případě WndProc, nastavit handled tak, aby false indikoval, že zpráva nebyla zpracována a vrácena 0. Pro DestroyWindowCore, prostě zničit okno.

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

Hostování ovládacího prvku na stránce

Chcete-li hostovat ovládací prvek na stránce, nejprve vytvoříte novou instanci ControlHost třídy. Předejte výšku a šířku prvku ohraničení, který obsahuje ovládací prvek (ControlHostElement) konstruktoru ControlHost . Tím zajistíte správnou velikost listboxu. Pak hostovat ovládací prvek na stránce přiřazením ControlHost objektu Child k vlastnosti hostitele Border.

Ukázka připojí obslužnou rutinu k MessageHook události příjmu ControlHost zpráv z ovládacího prvku. Tato událost se vyvolá pro každou zprávu poslanou do hostovaného okna. V tomto případě se jedná o zprávy odeslané do okna, které zabalí skutečný ovládací prvek ListBox, včetně oznámení z ovládacího prvku. Ukázka volá SendMessage k získání informací z ovládacího prvku a úpravě jeho obsahu. Podrobnosti o tom, jak stránka komunikuje s ovládacím prvku, jsou popsány v další části.

Poznámka:

Všimněte si, že existují dvě deklarace PInvoke pro SendMessage. To je nezbytné, protože jeden používá wParam parametr k předání řetězce a druhý ho používá k předání celého čísla. Pro každý podpis potřebujete samostatnou deklaraci, abyste měli jistotu, že jsou data správně zařazována.

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

Implementace komunikace mezi ovládacím prvku a stránkou

Ovládací prvek můžete manipulovat odesláním zpráv systému Windows. Ovládací prvek vás upozorní, když s ním uživatel komunikuje odesláním oznámení do okna hostitele. Hostování ovládacího prvku ListBox Win32 v ukázce WPF obsahuje uživatelské rozhraní, které poskytuje několik příkladů, jak to funguje:

  • Připojte položku do seznamu.

  • Odstranění vybrané položky ze seznamu

  • Zobrazí text aktuálně vybrané položky.

  • Zobrazí počet položek v seznamu.

Uživatel může také vybrat položku v seznamu kliknutím na ni, stejně jako u konvenční aplikace Win32. Zobrazená data se aktualizují pokaždé, když uživatel změní stav seznamu výběrem, přidáním nebo připojením položky.

Chcete-li připojit položky, odešlete seznam LB_ADDSTRING zprávy. Pokud chcete odstranit položky, odešlete LB_GETCURSEL index aktuálního výběru a pak LB_DELETESTRING položku odstraňte. Ukázka také odešle LB_GETCOUNTa použije vrácenou hodnotu k aktualizaci zobrazení, které zobrazuje počet položek. Obě tyto instance SendMessage použití jedné z DEklarací PInvoke probírané v předchozí části.

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

Když uživatel vybere položku nebo změní svůj výběr, ovládací prvek upozorní okno hostitele odesláním WM_COMMAND zprávy, která vyvolá MessageHook událost stránky. Obslužná rutina obdrží stejné informace jako hlavní okno okna okna hostitele. Předává také odkaz na logickou hodnotu. handled Nastavíte handled tak, abyste true označili, že jste zprávu zpracovali a není potřeba žádné další zpracování.

WM_COMMAND je odeslán z různých důvodů, takže je nutné zkontrolovat ID oznámení, abyste zjistili, jestli se jedná o událost, kterou chcete zpracovat. ID je obsaženo ve vysokém slově parametru wParam . Ukázka k extrakci ID používá bitové operátory. Pokud uživatel provedl nebo změnil svůj výběr, BUDE LBN_SELCHANGEID .

Po LBN_SELCHANGE přijetí získá ukázka index vybrané položky odesláním ovládacího prvku LB_GETCURSEL zprávu. Pokud chcete získat text, nejprve vytvoříte .StringBuilder Potom ovládací prvek LB_GETTEXT odešlete zprávu. Předejte prázdný StringBuilder objekt jako wParam parametr. Když SendMessage se vrátí, StringBuilder bude obsahovat text vybrané položky. Toto použití SendMessage vyžaduje ještě další deklaraci PInvoke.

Nakonec nastavte handled na true označení, že zpráva byla zpracována.

Viz také