Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Program Windows Presentation Foundation (WPF) udostępnia bogate środowisko do tworzenia aplikacji. Jednak jeśli masz znaczną inwestycję w kod Win32, bardziej skuteczne może być ponowne użycie co najmniej jednego kodu w aplikacji WPF, a nie ponowne zapisywanie go całkowicie. WPF zapewnia prosty mechanizm hostowania okna Win32 na stronie WPF.
W tym temacie opisano aplikację, hostowanie kontrolki Win32 ListBox w przykładowymWPF, które hostuje kontrolkę pola listy Win32. Tę ogólną procedurę można rozszerzyć na hostowanie dowolnego okna Win32.
Wymagania
W tym temacie założono podstawową znajomość programowania zarówno WPF, jak i interfejsu API systemu Windows. Aby zapoznać się z podstawowym wprowadzeniem do programowania WPF, zobacz Wprowadzenie. Aby zapoznać się z programowaniem interfejsu API systemu Windows, zobacz dowolną z licznych książek na ten temat, w szczególności Programming Windows autorstwa Charlesa Petzolda.
Ponieważ przykład dołączony do tego tematu jest implementowany w języku C#, korzysta z usług Invocation Services (PInvoke) platformy w celu uzyskania dostępu do interfejsu API systemu Windows. Znajomość funkcji PInvoke jest pomocna, ale nie niezbędna.
Uwaga / Notatka
Ten temat zawiera szereg przykładów kodu ze skojarzonego przykładu. Jednak w celu zapewnienia czytelności nie zawiera kompletnego przykładowego kodu. Możesz uzyskać lub wyświetlić pełny kod z hostowanie kontrolki Win32 ListBox w przykładzie WPF.
Procedura podstawowa
W tej sekcji opisano podstawową procedurę hostowania okna Win32 na stronie WPF. Pozostałe sekcje zawierają szczegółowe informacje o poszczególnych krokach.
Podstawowa procedura hostingu to:
Zaimplementuj stronę WPF do hostowania okna. Jedną z technik jest utworzenie elementu Border w celu zarezerwowania sekcji strony dla hostowanego okna.
Zaimplementuj klasę do hostowania kontrolki dziedziczonej z HwndHost.
W tej klasie, przesłoń element składowy HwndHostklasy BuildWindowCore.
Utwórz hostowane okno jako element podrzędny okna zawierającego stronę WPF. Chociaż konwencjonalne programowanie WPF nie musi jawnie korzystać z niego, strona hostingu jest oknem z uchwytem (HWND). Otrzymujesz stronę HWND za pośrednictwem parametru
hwndParent
metody BuildWindowCore. Hostowane okno powinno zostać utworzone jako element podrzędny tego HWND.Po utworzeniu okna hosta zwróć wartość HWND okna hostowanego. Jeśli chcesz hostować co najmniej jedną kontrolkę Win32, zazwyczaj utworzysz okno hosta jako podrzędne do HWND i sprawisz, że kontrolki będą dziećmi tego okna hosta. Opakowanie kontrolek w oknie hosta zapewnia prosty sposób, w jaki strona WPF może odbierać powiadomienia z kontrolek, co rozwiązuje niektóre konkretne problemy Win32 z powiadomieniami przez granicę HWND.
Obsługa wybranych komunikatów wysyłanych do okna hosta, takich jak powiadomienia z kontrolek podrzędnych. Istnieją dwa sposoby, aby to zrobić.
Jeśli wolisz obsługiwać komunikaty w klasie hostingu, przesłoń metodę WndProc klasy HwndHost.
Jeśli wolisz obsługiwać komunikaty przez platformę WPF, obsłuż zdarzenie HwndHost klasy MessageHook w kodzie. To zdarzenie występuje dla każdego komunikatu otrzymanego przez hostowane okno. Jeśli wybierzesz tę opcję, nadal musisz zastąpić WndProc, ale potrzebujesz tylko minimalnej implementacji.
Zastąpij metody DestroyWindowCore i WndProcHwndHost. Należy zastąpić te metody, aby spełnić wymagania umowy HwndHost, ale może być konieczne tylko zapewnienie minimalnej implementacji.
W pliku związanego z kodem utwórz wystąpienie klasy hostującej kontrolkę i ustaw je jako element podrzędny elementu Border przeznaczonego do hostowania okna.
Komunikowanie się z oknem hostowanym przez wysłanie do niego komunikatów systemu Microsoft Windows i obsługę komunikatów z okien podrzędnych, takich jak powiadomienia wysyłane przez kontrolki.
Implementowanie układu strony
Układ strony WPF hostujący kontrolkę ListBox składa się z dwóch regionów. Po lewej stronie znajduje się kilka kontrolek WPF, które udostępniają interfejs użytkownika, który umożliwia manipulowanie kontrolką Win32. Prawy górny róg strony ma region kwadratowy dla hostowanej kontrolki ListBox.
Kod do zaimplementowania tego układu jest dość prosty. Element główny jest DockPanel, który ma dwa elementy podrzędne. Pierwszy to element Border hostujący kontrolkę ListBox. Zajmuje 200x200 kwadrat w prawym górnym rogu strony. Drugi to element StackPanel zawierający zestaw kontrolek WPF, które wyświetlają informacje i umożliwiają manipulowanie kontrolką ListBox przez ustawienie uwidocznionych właściwości współdziałania. Dla każdego z elementów podrzędnych StackPanel, sprawdź materiał referencyjny dotyczący różnych elementów użytych do uzyskania szczegółowych informacji o tym, czym są te elementy lub jakie mają zastosowanie. Elementy te są wymienione w poniższym przykładowym kodzie, ale nie zostaną tutaj wyjaśnione. Podstawowy model współdziałania nie wymaga ich użycia; są one udostępniane, aby dodać pewną interaktywność do przykładu.
<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>
Implementowanie klasy do hostowania kontrolki Microsoft Win32
Rdzeniem tego przykładu jest klasa, która faktycznie hostuje kontrolkę, ControlHost.cs. Dziedziczy z HwndHost. Konstruktor przyjmuje dwa parametry, wysokość i szerokość, które odpowiadają wysokości i szerokości elementu Border hostujące kontrolkę ListBox. Te wartości są używane później, aby upewnić się, że rozmiar kontrolki jest zgodny z elementem Border.
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
Istnieje również zestaw stałych. Te stałe są w dużej mierze pobierane z winuser.h i umożliwiają używanie konwencjonalnych nazw podczas wywoływania funkcji 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
Nadpisz BuildWindowCore, aby utworzyć okno Microsoft Win32
Zastąpisz tę metodę, aby utworzyć okno Win32, które będzie hostowane przez stronę, i nawiązać połączenie między oknem a stroną. Ponieważ ten przykład obejmuje hostowanie kontrolki ListBox, tworzone są dwa okna. Pierwszy to okno, które jest rzeczywiście hostowane przez stronę WPF. Kontrolka ListBox jest tworzona jako element podrzędny tego okna.
Przyczyną tego podejścia jest uproszczenie procesu odbierania powiadomień z kontrolki. Klasa HwndHost umożliwia przetwarzanie komunikatów wysyłanych do okna, które hostuje. W przypadku bezpośredniego hostowania kontrolki Win32 otrzymujesz komunikaty wysyłane do wewnętrznej pętli komunikatów tej kontrolki. Kontrolkę można wyświetlić i wysłać do niej komunikaty, ale nie otrzymasz powiadomień wysyłanych przez kontrolkę do okna nadrzędnego. Oznacza to między innymi, że nie ma możliwości wykrywania, gdy użytkownik wchodzi w interakcję z kontrolką. Zamiast tego utwórz okno hosta i ustaw kontrolkę jako element podrzędny tego okna. Dzięki temu można przetwarzać komunikaty dla okna hosta, w tym powiadomienia wysyłane do niego przez kontrolkę. Dla wygody, ponieważ okno hosta jest czymś więcej niż tylko prostą otoczką dla kontrolki, będziemy odnosić się do niej jako do kontrolki ListBox.
Tworzenie okna hosta i kontrolki ListBox
Możesz użyć funkcji PInvoke, aby utworzyć okno hosta dla kontrolki, tworząc i rejestrując klasę okien itd. Jednak znacznie prostszą metodą jest utworzenie okna ze wstępnie zdefiniowaną klasą okien "statycznych". Zapewnia to procedurę okna wymaganą do odbierania powiadomień z kontrolki i wymaga minimalnej ilości kodu.
HWND kontrolki jest uwidoczniona za pośrednictwem właściwości tylko do odczytu, tak aby strona hosta mogła jej używać do wysyłania komunikatów do kontrolki.
public IntPtr hwndListBox
{
get { return hwndControl; }
}
Public ReadOnly Property hwndListBox() As IntPtr
Get
Return hwndControl
End Get
End Property
Kontrolka ListBox jest tworzona jako element podrzędny okna hosta. Wysokość i szerokość obu okien są ustawione na wartości przekazane do konstruktora, omówione powyżej. Dzięki temu rozmiar okna hosta i kontrolki są identyczne z obszarem zarezerwowanym na stronie. Po utworzeniu okien, przykładowa aplikacja zwraca obiekt HandleRef zawierający HWND okna hosta.
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
Implementowanie systemu DestroyWindow i WndProc
Oprócz BuildWindowCore, należy również przesłonić metody WndProc i DestroyWindowCore w klasie HwndHost. W tym przykładzie komunikaty dla kontrolki są obsługiwane przez program obsługi MessageHook, dlatego implementacja WndProc i DestroyWindowCore jest minimalna. W przypadku WndProcustaw handled
na false
, aby wskazać, że komunikat nie został obsłużony i zwróć 0. W przypadku DestroyWindowCorepo prostu zniszczyć 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
Hostowanie kontrolki na stronie
Aby hostować kontrolkę na stronie, należy najpierw utworzyć nowe wystąpienie klasy ControlHost
. Przekaż wysokość i szerokość elementu obramowania zawierającego kontrolkę (ControlHostElement
) do konstruktora ControlHost
. Dzięki temu pole ListBox ma prawidłowy rozmiar. Następnie należy umieścić kontrolkę na stronie, przypisując obiekt ControlHost
do właściwości Child hosta Border.
Przykład dołącza procedurę obsługi zdarzeń do zdarzenia MessageHook obiektu ControlHost
, aby odbierać komunikaty z komponentu sterującego. To zdarzenie jest zgłaszane dla każdego komunikatu wysyłanego do hostowanego okna. W takim przypadku są to komunikaty wysyłane do okna, które opakowuje rzeczywistą kontrolkę ListBox, w tym powiadomienia z kontrolki. Przykład wywołuje funkcję SendMessage, aby uzyskać informacje z kontrolki i zmodyfikować jej zawartość. Szczegółowe informacje o tym, jak strona komunikuje się z kontrolką, zostały omówione w następnej sekcji.
Uwaga / Notatka
Zwróć uwagę, że istnieją dwie deklaracje PInvoke dla funkcji SendMessage. Jest to konieczne, ponieważ jeden używa parametru wParam
do przekazania ciągu, a drugi używa go do przekazania liczby całkowitej. Potrzebna jest osobna deklaracja dla każdego podpisu, aby upewnić się, że dane są prawidłowo przesyłane.
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
Implementowanie komunikacji między kontrolką a stroną
Kontrolkę można manipulować, wysyłając komunikaty systemu Windows. Kontrolka powiadamia o tym, kiedy użytkownik wchodzi z nim w interakcję, wysyłając powiadomienia do okna hosta. Przykład dotyczący hostowania kontrolki ListBox Win32 w środowisku WPF zawiera interfejs użytkownika, który przedstawia kilka przykładów działania tej funkcji:
Dołącz element do listy.
Usuń wybrany element z listy
Wyświetl tekst aktualnie wybranego elementu.
Wyświetl liczbę elementów na liście.
Użytkownik może również wybrać element w polu listy, klikając go tak samo jak w przypadku konwencjonalnej aplikacji Win32. Wyświetlane dane są aktualizowane za każdym razem, gdy użytkownik zmienia stan pola listy, wybierając, dodając lub dołączając element.
Aby dołączyć elementy, wyślij do pola listy komunikat LB_ADDSTRING
. Aby usunąć elementy, wyślij LB_GETCURSEL
, aby pobrać indeks bieżącego zaznaczenia, a następnie wyślij LB_DELETESTRING
, aby usunąć element. Przykład wysyła również LB_GETCOUNT
i używa zwróconej wartości do zaktualizowania ekranu, który pokazuje liczbę elementów. Oba te wystąpienia SendMessage
używają jednej z deklaracji PInvoke omówionych w poprzedniej sekcji.
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
Gdy użytkownik wybierze element lub zmieni wybór, kontrolka powiadamia okno hosta, wysyłając mu komunikat WM_COMMAND
, który zgłasza zdarzenie MessageHook dla strony. Procedura obsługi otrzymuje te same informacje co główna procedura okna hosta. Przekazuje również odwołanie do wartości logicznej handled
. Ustaw handled
na true
, aby wskazać, że komunikat został obsłużony i nie jest potrzebne żadne dalsze przetwarzanie.
WM_COMMAND
jest wysyłany z różnych powodów, dlatego należy sprawdzić identyfikator powiadomienia, aby określić, czy jest to zdarzenie, które chcesz obsłużyć. Identyfikator jest zawarty w wysokim słowie parametru wParam
. W przykładzie użyto operatorów bitowych do wyodrębnienia identyfikatora. Jeśli użytkownik dokonał wyboru lub zmienił jego wybór, identyfikator będzie LBN_SELCHANGE
.
Po odebraniu LBN_SELCHANGE
przykład uzyskuje indeks wybranego elementu poprzez wysłanie do kontroli polecenia LB_GETCURSEL
. Aby uzyskać tekst, należy najpierw utworzyć StringBuilder. Następnie należy wysłać kontrolkę wiadomości LB_GETTEXT
. Przekaż pusty obiekt StringBuilder jako parametr wParam
. Gdy SendMessage
wróci, StringBuilder będzie zawierać tekst wybranego elementu. Użycie SendMessage
wymaga jeszcze innej deklaracji PInvoke.
Na koniec ustaw handled
na true
, aby wskazać, że komunikat został obsłużony.
Zobacz także
.NET Desktop feedback