Demonstra Passo a passo: Hospedar um controle Win32 no WPF
O Windows Presentation Foundation (WPF) fornece um ambiente avançado para a criação de aplicativos. No entanto, quando você tem um investimento substancial em código Win32, pode ser mais eficaz reutilizar pelo menos parte desse código em seu aplicativo WPF em vez de reescrevê-lo completamente. WPF fornece um mecanismo direto para hospedar uma janela Win32, em uma página WPF.
Este tópico orienta você por um aplicativo, Hospedando um controle Win32 ListBox no exemplo WPF, que hospeda um controle de caixa de listagem Win32. Este procedimento geral pode ser estendido para hospedar qualquer janela do Win32.
Requisitos
Este tópico pressupõe uma familiaridade básica com a programação do WPF e da API do Windows. Para obter uma introdução básica à programação do WPF, consulte Introdução. Para obter uma introdução à programação de API do Windows, consulte qualquer um dos vários livros sobre o assunto, em particular Programming Windows de Charles Petzold.
Como o exemplo que acompanha este tópico é implementado em C#, ele usa o PInvoke (Platform Invocation Services) para acessar a API do Windows. Alguma familiaridade com o PInvoke é útil, mas não essencial.
Observação
Este tópico inclui alguns exemplos de código da amostra associada. No entanto, para facilitar a leitura, não inclui o código de exemplo completo. É possível obter ou exibir o código completo de Amostra de hospedando um controle Win32 ListBox no WPF.
O procedimento básico
Esta seção descreve o procedimento básico para hospedar uma janela Win32 em uma página WPF. As seções restantes apresentam detalhes de cada etapa.
O procedimento básico de hospedagem é:
Implemente uma página WPF para hospedar a janela. Uma técnica é criar um Border elemento para reservar uma seção da página para a janela hospedada.
Implemente uma classe para hospedar o controle que herda do HwndHost.
Nessa classe, substitua o membro BuildWindowCoreda HwndHost classe .
Crie a janela hospedada como um filho da janela que contém a página WPF. Embora a programação WPF convencional não precise fazer uso explícito dela, a página de hospedagem é uma janela com um identificador (HWND). Você recebe a página HWND através do
hwndParent
parâmetro do BuildWindowCore método. A janela hospedada deve ser criada como um filho desse HWND.Depois de criar a janela do host, retorne o HWND da janela hospedada. Se você deseja hospedar um ou mais controles Win32, você normalmente cria uma janela de host como um filho do HWND e tornar os controles filhos dessa janela de host. Encapsular os controles em uma janela de host fornece uma maneira simples para sua página WPF para receber notificações dos controles, que lida com alguns problemas específicos do Win32 com notificações através do limite HWND.
Manipule as mensagens selecionadas enviadas à janela de host, como notificações dos controles filho. Há duas maneiras de fazer isso.
Se você preferir manipular mensagens em sua classe de hospedagem, substitua o WndProcHwndHost método da classe.
Se você preferir que o WPF manipule as mensagens, manipule o HwndHost evento de classe MessageHook em seu code-behind. Esse evento ocorre para cada mensagem recebida pela janela hospedada. Se você escolher essa opção, ainda deverá substituir WndProco , mas precisará apenas de uma implementação mínima.
Substitua os métodos e WndProc de DestroyWindowCoreHwndHost. Você deve substituir esses métodos para satisfazer o HwndHost contrato, mas talvez seja necessário fornecer apenas uma implementação mínima.
No arquivo code-behind, crie uma instância da classe de hospedagem de controle e torne-a um filho do Border elemento que se destina a hospedar a janela.
Comunique-se com a janela hospedada enviando-lhe mensagens do Microsoft Windows e manipulando mensagens de suas janelas filhas, como notificações enviadas por controles.
Implementar o layout da página
O layout da página WPF que hospeda o controle ListBox consiste em duas regiões. O lado esquerdo da página hospeda vários controles WPF que fornecem uma interface do usuário (UI) que permite manipular o controle Win32. O canto superior direito da página tem uma região quadrada para o controle ListBox hospedado.
O código para implementar esse layout é bastante simples. O elemento raiz é um DockPanel que tem dois elementos filho. O primeiro é um Border elemento que hospeda o controle ListBox. Ele ocupa um quadrado de 200x200 no canto superior direito da página. O segundo é um elemento que contém um StackPanel conjunto de controles WPF que exibem informações e permitem que você manipule o controle ListBox definindo propriedades de interoperação expostas. Para cada um dos elementos que são filhos do , consulte o material de referência para os vários elementos usados para obter detalhes sobre o que esses elementos são ou o que eles fazem, eles estão listados no código de exemplo abaixo, mas não serão explicados aqui (o modelo básico de StackPanelinteroperação não requer nenhum deles, eles são fornecidos para adicionar alguma interatividade ao exemplo).
<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>
Implementar uma classe para hospedar o controle Microsoft Win32
O núcleo dessa amostra é a classe que realmente hospeda o controle: ControlHost.cs. Herda de HwndHost. O construtor usa dois parâmetros, height e width, que correspondem à altura e largura do elemento que hospeda Border o controle ListBox. Esses valores são usados posteriormente para garantir que o tamanho do controle corresponda ao Border elemento.
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
Também existe um conjunto de constantes. Essas constantes são em grande parte retiradas de Winuser.h e permitem que você use nomes convencionais ao chamar funções 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
Substituir o BuildWindowCore para criar a janela do Microsoft Win32
Você substitui esse método para criar a janela Win32 que será hospedada pela página e fazer a conexão entre a janela e a página. Como essa amostra envolve a hospedagem de um controle ListBox, duas janelas são criadas. A primeira é a janela que é realmente hospedada pela página WPF. O controle ListBox é criado como um filho dessa janela.
A razão para essa abordagem é simplificar o processo de recebimento de notificações do controle. A HwndHost classe permite que você processe mensagens enviadas para a janela que está hospedando. Se você hospedar um controle Win32 diretamente, você receberá as mensagens enviadas para o loop de mensagem interno do controle. É possível exibir o controle e lhe enviar mensagens, mas você não receberá as notificações que o controle envia para a janela pai. Isso significa, entre outras coisas, que você não tem nenhuma maneira de detectar quando o usuário interage com o controle. Em vez disso, crie uma janela de host e transforme o controle em filho dessa janela. Assim, pode processar as mensagens para a janela de host, incluindo as notificações enviadas a ela pelo controle. Por uma questão de conveniência, como a janela de host é mais que um wrapper simples para o controle, o pacote será chamado de controle ListBox.
Criar a janela de host e o controle ListBox
Você pode usar PInvoke para criar uma janela de host para o controle criando e registrando uma classe de janela e assim por diante. No entanto, uma abordagem muito mais simples é criar uma janela com a classe de janela predefinida “estática”. Isso proporciona o procedimento de janela de que você precisa para receber notificações do controle e requer o mínimo de codificação.
O HWND do controle é exposto por meio de uma propriedade somente leitura; assim, a página de host pode usá-lo para enviar mensagens para o controle.
public IntPtr hwndListBox
{
get { return hwndControl; }
}
Public ReadOnly Property hwndListBox() As IntPtr
Get
Return hwndControl
End Get
End Property
O controle ListBox é criado como um filho da janela de host. A altura e a largura de ambas as janelas são definidas para os valores passados para o construtor, discutidos acima. Isso garante que o tamanho da janela de host e do controle sejam idênticos à área reservada na página. Depois que as janelas são criadas, o exemplo retorna um HandleRef objeto que contém o HWND da janela do host.
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
Implementar DestroyWindow e WndProc
Além do , você também deve substituir os métodos e DestroyWindowCore do BuildWindowCoreHwndHost.WndProc Neste exemplo, as mensagens para o controle são manipuladas pelo MessageHook manipulador, portanto, a implementação de WndProc e DestroyWindowCore é mínima. No caso de WndProc, defina handled
como false
indicar que a mensagem não foi manipulada e retornar 0. Pois DestroyWindowCore, basta destruir a janela.
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
Hospedar o controle na página
Para hospedar o controle na página, primeiro crie uma nova instância da ControlHost
classe. Passe a altura e a largura do elemento border que contém o controle (ControlHostElement
) para o ControlHost
construtor. Isso garante que o ListBox será dimensionado corretamente. Em seguida, hospede o controle na página atribuindo o ControlHost
objeto à Child propriedade do host Border.
O exemplo anexa um manipulador ao MessageHook evento do para receber mensagens do ControlHost
controle. Esse evento é gerado para cada mensagem enviada para a janela hospedada. Nesse caso, são as mensagens enviadas à janela que encapsula o verdadeiro controle ListBox, incluindo notificações do controle. O exemplo chama SendMessage para obter informações do controle e modificar seu conteúdo. Os detalhes de como a página se comunica com o controle são discutidos na próxima seção.
Observação
Observe que há duas declarações PInvoke para SendMessage. Isso é necessário porque um usa o parâmetro para passar uma cadeia de caracteres e o outro o wParam
usa para passar um inteiro. Você precisa de uma declaração separada para cada assinatura a fim de garantir que o marshaling dos dados será realizado corretamente.
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
Implementar comunicação entre o controle e a página
Você manipula o controle enviando-lhe mensagens do Windows. Para notificar você de que o usuário interagiu com ele, o controle envia notificações para a janela de host. O exemplo de hospedagem de um controle ListBox Win32 no WPF inclui uma interface do usuário que fornece vários exemplos de como isso funciona:
Acrescentar um novo item à lista.
Excluir o item selecionado da lista
Exibir o texto do item selecionado atualmente.
Exibir o número de itens na lista.
O usuário também pode selecionar um item na caixa de listagem clicando nele, assim como faria para um aplicativo Win32 convencional. Os dados exibidos são atualizados sempre que o usuário altera o estado da caixa de listagem ao selecionar, adicionar ou acrescentar um item.
Para acrescentar itens, envie uma mensagem à caixa de LB_ADDSTRING
listagem. Para excluir itens, envie LB_GETCURSEL
para obter o índice da seleção atual e, em seguida, LB_DELETESTRING
para excluir o item. O exemplo também envia LB_GETCOUNT
e usa o valor retornado para atualizar a exibição que mostra o número de itens. Ambas as instâncias de SendMessage
uso de uma das declarações PInvoke discutidas na seção anterior.
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
Quando o usuário seleciona um item ou altera sua seleção, o controle notifica a janela do host enviando-lhe uma WM_COMMAND
mensagem, que gera o MessageHook evento para a página. O manipulador recebe as mesmas informações que o procedimento de janela principal da janela de host. Também passa uma referência a um valor booliano: handled
. Você define handled
como true
para indicar que você manipulou a mensagem e nenhum processamento adicional é necessário.
WM_COMMAND
é enviado por vários motivos, portanto, você deve examinar a ID de notificação para determinar se é um evento que você deseja manipular. O ID está contido na palavra alta do wParam
parâmetro. O exemplo usa operadores bit a bit para extrair o ID. Se o usuário tiver feito ou alterado sua seleção, o ID será LBN_SELCHANGE
.
Quando LBN_SELCHANGE
é recebido, o exemplo obtém o índice do item selecionado enviando uma LB_GETCURSEL
mensagem ao controle. Para obter o texto, primeiro crie um StringBuilderarquivo . Em seguida, você envia uma LB_GETTEXT
mensagem ao controle. Passe o objeto vazio StringBuilder como o wParam
parâmetro. Quando SendMessage
retorna, o conterá o StringBuilder texto do item selecionado. Esse uso de SendMessage
requer ainda outra declaração PInvoke.
Finalmente, defina handled
como true
para indicar que a mensagem foi manipulada.
Confira também
.NET Desktop feedback