Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Windows Presentation Foundation (WPF) ger en omfattande miljö för att skapa program. Men när du har en betydande investering i Win32-kod kan det vara mer effektivt att återanvända åtminstone en del av koden i wpf-programmet i stället för att skriva om den helt. WPF tillhandahåller en enkel mekanism för att vara värd för ett Win32-fönster på en WPF-sida.
Det här avsnittet vägleder dig genom ett program, Exempel på att integrera en Win32 ListBox-kontroll i WPF, som innehåller en Win32-listrutekontroll. Den här allmänna proceduren kan utökas till att vara värd för alla Win32-fönster.
Kravspecifikation
Det här avsnittet förutsätter grundläggande kunskaper om både WPF- och Windows API-programmering. En grundläggande introduktion till WPF-programmering finns i Komma igång. En introduktion till Programmering av Windows API finns i någon av de många böckerna i ämnet, särskilt Programmeringsfönster av Charles Petzold.
Eftersom exemplet som medföljer det här avsnittet implementeras i C# använder det plattformsanropstjänster (PInvoke) för att få åtkomst till Windows-API:et. Viss kunskap om PInvoke är användbart men inte nödvändigt.
Anmärkning
Det här avsnittet innehåller ett antal kodexempel från det associerade exemplet. För läsbarhet innehåller den dock inte den fullständiga exempelkoden. Du kan hämta eller visa fullständig kod från Värda en Win32 ListBox-kontroll i ett WPF-exempelprogram.
Den grundläggande proceduren
Det här avsnittet beskriver den grundläggande proceduren för att vara värd för ett Win32-fönster på en WPF-sida. De återstående avsnitten går igenom information om varje steg.
Den grundläggande värdproceduren är:
Implementera en WPF-sida som värd för fönstret. En teknik är att skapa ett Border element för att reservera ett avsnitt av sidan för det värdbaserade fönstret.
Implementera en klass som värd för kontrollen som ärver från HwndHost.
I den klassen åsidosätter du HwndHost klassmedlemmen BuildWindowCore.
Skapa det värdbaserade fönstret som ett underordnat fönster som innehåller WPF-sidan. Även om konventionell WPF-programmering inte uttryckligen behöver använda den, är värdsidan ett fönster med ett handtag (HWND). Du får sidan HWND via
hwndParent-parametern för metoden BuildWindowCore. Det värdbaserade fönstret ska skapas som ett barn till detta HWND.När du har skapat värdfönstret returnerar du HWND för det värdbaserade fönstret. Om du vill använda en eller flera Win32-kontroller skapar du vanligtvis ett värdfönster som ett barnfönster av HWND och gör kontrollerna till barnfönster inom det värdfönstret. Att omsluta kontrollerna i ett värdfönster är ett enkelt sätt för WPF-sidan att effektivt ta emot meddelanden från kontrollerna och hantera specifika Win32-problem med meddelanden som korsar HWND-gränsen.
Hantera markerade meddelanden som skickas till värdfönstret, till exempel meddelanden från underordnade kontroller. Det finns två sätt att göra detta på.
Om du föredrar att hantera meddelanden i din värdklass, ska du åsidosätta WndProc-metoden i HwndHost-klassen.
Om du föredrar att meddelandena hanteras av WPF, hanterar du händelsen HwndHost i din klasskod MessageHook. Den här händelsen inträffar för varje meddelande som tas emot av värdfönstret. Om du väljer det här alternativet måste du fortfarande åsidosätta WndProc, men du behöver bara en minimal implementering.
Åsidosätt metoderna DestroyWindowCore och WndProc i HwndHost. Du måste åsidosätta dessa metoder för att uppfylla HwndHost kontraktet, men du kanske bara behöver tillhandahålla en minimal implementering.
I filen bakom koden skapar du en instans av kontrollvärdklassen och gör den till underordnad elementet Border som är avsett att vara värd för fönstret.
Kommunicera med det värdbaserade fönstret genom att skicka Microsoft Windows-meddelanden och hantera meddelanden från dess underordnade fönster, till exempel meddelanden som skickas av kontroller.
Utför sidlayouten
Layouten för WPF-sidan som är värd för ListBox-kontrollen består av två regioner. Till vänster på sidan finns flera WPF-kontroller som tillhandahåller ett användargränssnitt (UI) som gör att du kan ändra Win32-kontrollen. Det övre högra hörnet på sidan har en kvadratregion för den värdbaserade ListBox-kontrollen.
Koden för att implementera den här layouten är ganska enkel. Rotelementet är ett DockPanel element som har två underordnade element. Det första är ett Border element som är värd för ListBox-kontrollen. Den upptar en 200x200 kvadrat i det övre högra hörnet på sidan. Det andra är ett StackPanel element som innehåller en uppsättning WPF-kontroller som visar information och gör att du kan ändra ListBox-kontrollen genom att ange exponerade interoperationsegenskaper. För vart och ett av StackPanelde element som är underordnade till , se referensmaterialet för de olika element som används för information om vad dessa element är eller vad de gör, dessa anges i exempelkoden nedan men förklaras inte här (den grundläggande samverkansmodellen kräver inte någon av dem, de tillhandahålls för att lägga till viss interaktivitet i exemplet).
<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>
Implementera en klass som värd för Microsoft Win32-kontrollen
Kärnan i det här exemplet är den klass som faktiskt är värd för kontrollen, ControlHost.cs. Den ärver från HwndHost. Konstruktorn tar två parametrar, höjd och bredd, vilket motsvarar höjden och bredden för elementet Border som är värd för ListBox-kontrollen. Dessa värden används senare för att säkerställa att kontrollens storlek matchar elementet 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
Det finns också en uppsättning konstanter. Dessa konstanter är till stor del hämtade från Winuser.h och gör att du kan använda konventionella namn när du anropar Win32-funktioner.
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
Åsidosätt BuildWindowCore för att skapa Microsoft Win32-fönstret
Du åsidosätter den här metoden för att skapa win32-fönstret som ska finnas på sidan och upprätta anslutningen mellan fönstret och sidan. Eftersom det här exemplet omfattar värd för en ListBox-kontroll skapas två fönster. Det första är fönstret som faktiskt hanteras av WPF-sidan. ListBox-kontrollen skapas som underordnad till det fönstret.
Anledningen till den här metoden är att förenkla processen med att ta emot meddelanden från kontrollen. Med HwndHost klassen kan du bearbeta meddelanden som skickas till fönstret som den är värd för. Om du är värd för en Win32-kontroll direkt får du meddelandena som skickas till kontrollens interna meddelandeloop. Du kan visa kontrollen och skicka meddelanden till den, men du får inte de meddelanden som kontrollen skickar till det överordnade fönstret. Det innebär bland annat att du inte har något sätt att identifiera när användaren interagerar med kontrollen. Skapa i stället ett värdfönster och gör kontrollen till underordnad det fönstret. På så sätt kan du bearbeta meddelandena för värdfönstret, inklusive meddelanden som skickas till den av kontrollen. För att förenkla, eftersom värdfönstret är lite mer än en enkel inramning för kontrollen, kallas paketet för en ListBox-kontroll.
Skapa värdfönstret och ListBox-kontrollen
Du kan använda PInvoke för att skapa ett värdfönster för kontrollen genom att skapa och registrera en fönsterklass och så vidare. En mycket enklare metod är dock att skapa ett fönster med den fördefinierade "statiska" fönsterklassen. Detta ger dig den fönsterprocedur som du behöver för att ta emot meddelanden från kontrollen och kräver minimal kodning.
HWND för kontrollen exponeras via en skrivskyddad egenskap, så att värdsidan kan använda den för att skicka meddelanden till kontrollen.
public IntPtr hwndListBox
{
get { return hwndControl; }
}
Public ReadOnly Property hwndListBox() As IntPtr
Get
Return hwndControl
End Get
End Property
ListBox-kontrollen skapas som underordnad av värdfönstret. Höjden och bredden för båda fönstren är inställda på de värden som skickas till konstruktorn, som beskrivs ovan. Detta säkerställer att storleken på värdfönstret och kontrollen är identisk med det reserverade området på sidan. När fönstren har skapats returnerar exemplet ett HandleRef objekt som innehåller värdfönstrets HWND.
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
Implementera DestroyWindow och WndProc
Förutom BuildWindowCore måste du också åsidosätta WndProc och DestroyWindowCore metoderna för HwndHost. I det här exemplet hanteras meddelandena för kontrollen av MessageHook hanteraren, vilket innebär att implementeringen av WndProc och DestroyWindowCore är minimal. I fallet av WndProc, ange handled till false för att indikera att meddelandet inte hanterades och returnera 0. För DestroyWindowCore, förstör helt enkelt fönstret.
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
Placera kontrollen på sidan
Om du vill vara värd för kontrollen på sidan skapar du först en ny instans av ControlHost klassen. Skicka höjd och bredd för kantlinjeelementet som innehåller kontrollen (ControlHostElement) till ControlHost konstruktorn. Detta säkerställer att ListBox är rätt storlek. Placera sedan kontrollen på sidan genom att tilldela ControlHost-objektet till Child-egenskapen för värden Border.
Exemplet kopplar en hanterare till MessageHook händelsen ControlHost för att ta emot meddelanden från kontrollen. Den här händelsen utlöses för varje meddelande som skickas till det värdbaserade fönstret. I det här fallet är det dessa meddelanden som skickas till fönstret som omsluter den faktiska ListBox-kontrollen, inklusive meddelanden från kontrollen. Exemplet anropar SendMessage för att hämta information från kontrollen och ändra dess innehåll. Information om hur sidan kommunicerar med kontrollen beskrivs i nästa avsnitt.
Anmärkning
Observera att det finns två PInvoke-deklarationer för SendMessage. Detta är nödvändigt eftersom en använder parametern wParam för att skicka en sträng och den andra använder den för att skicka ett heltal. Du behöver en separat deklaration för varje signatur för att säkerställa att data har konverterats korrekt.
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
Implementera kommunikation mellan kontrollen och sidan
Du ändrar kontrollen genom att skicka Windows-meddelanden. Kontrollen meddelar dig när användaren interagerar med den genom att skicka meddelanden till värdfönstret. Exemplet Värd för en Win32 ListBox-kontroll i WPF innehåller ett användargränssnitt som innehåller flera exempel på hur detta fungerar:
Lägg till ett objekt i listan.
Ta bort det markerade objektet från listan
Visa texten för det markerade objektet.
Visa antalet objekt i listan.
Användaren kan också välja ett objekt i listrutan genom att klicka på det, precis som för ett konventionellt Win32-program. De data som visas uppdateras varje gång användaren ändrar listrutans tillstånd genom att välja, lägga till eller lägga till ett objekt.
Om du vill lägga till objekt skickar du listrutan ett LB_ADDSTRING meddelande. Om du vill ta bort objekt skickar du LB_GETCURSEL för att hämta indexet för den aktuella markeringen och sedan LB_DELETESTRING ta bort objektet. Exemplet skickar LB_GETCOUNTockså och använder det returnerade värdet för att uppdatera visningen som visar antalet objekt. Båda dessa instanser av SendMessage använder en av PInvoke-deklarationerna som diskuterades i föregående avsnitt.
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
När användaren väljer ett objekt eller ändrar sitt val meddelar kontrollen värdfönstret genom att skicka ett WM_COMMAND meddelande som genererar MessageHook händelsen för sidan. Hanteraren får samma information som huvudfönsterproceduren i värdfönstret. Den skickar också en referens till ett booleskt värde, handled. Du ställer in handled på true för att ange att du har hanterat meddelandet och att ingen ytterligare bearbetning behövs.
WM_COMMAND skickas av olika orsaker, så du måste undersöka meddelande-ID:t för att avgöra om det är en händelse som du vill hantera. ID:t finns i parameterns wParam höga ord. Exemplet använder bitvisa operatorer för att extrahera ID. Om användaren har gjort eller ändrat sitt val kommer ID:t att bli LBN_SELCHANGE.
När LBN_SELCHANGE tas emot hämtar exemplet indexet för det markerade objektet genom att skicka kontrollen ett LB_GETCURSEL meddelande. Om du vill hämta texten skapar du först en StringBuilder. Sedan skickar du kontrollen ett LB_GETTEXT meddelande. Skicka det tomma StringBuilder objektet som wParam parameter. När SendMessage returnerar kommer StringBuilder att innehålla texten för det markerade elementet. Den här användningen av SendMessage kräver ännu en PInvoke-deklaration.
Slutligen, sätt handled till true för att indikera att meddelandet har hanterats.
Se även
.NET Desktop feedback