Creazione di sottoclassi per i controlli tramite una routine di finestra gestita

Aggiornamento: novembre 2007

In .NET Compact Framework è disponibile una funzionalità che consente al codice nativo di chiamare il codice gestito utilizzando un delegato di callback. Mediante la creazione di una sottoclasse per un controllo gestito in modo che riceva un callback dal controllo nativo corrispondente, è possibile creare controlli con funzionalità non direttamente disponibili in .NET Compact Framework.

Questo argomento contiene informazioni avanzate destinate agli sviluppatori dotati di una conoscenza approfondita della programmazione in Windows e della creazione di sottoclassi per i controlli. Per creare una sottoclasse per un controllo, è infatti necessario conoscere nei minimi dettagli il controllo nativo e come è mappato alla funzionalità che si intende fornire nell'estensione al controllo gestito. Per fornire la funzionalità desiderata, è necessario sapere quali messaggi di Windows monitorare e quali funzioni native di Windows Embedded CE richiamare.

In questo argomento viene descritta la creazione di sottoclassi per i controlli TreeView e Button, mentre negli argomenti elencati di seguito vengono forniti gli esempi di codice e le istruzioni per generare le applicazioni.

Argomento con procedura

Dimostrazione

Procedura: creare una sottoclasse di TreeView tramite callback nativi

Creazione di una sottoclasse del controllo TreeView per la creazione di un'implementazione dell'evento NodeMouseClick. In .NET Compact Framework questo metodo non è supportato direttamente poiché è necessario limitarne le dimensioni per le risorse vincolate.

Procedura: creare una sottoclasse di Button tramite callback nativi

Creazione di una sottoclasse del controllo Button per la visualizzazione di un riempimento sfumato colorato.

Questo pulsante viene fornito principalmente per illustrare l'utilizzo della creazione di sottoclassi e dei callback. Per creare in modo più semplice un pulsante con riempimento sfumato, vedere Procedura: visualizzare un riempimento sfumato.

Entrambi questi programmi per la creazione di sottoclassi includono la classe WndProcHooker e una classe di supporto di strutture Win32 native, dichiarazioni di richiamo piattaforma e un delegato WndProc. Per i listati di codice, vedere Procedura: utilizzare una classe per associare le routine di Windows e Procedura: utilizzare una classe di supporto per richiami piattaforma.

La classe WndProcHooker consente di avere una finestra o un controllo nativo che richiama un callback a codice gestito quando viene ricevuto un determinato messaggio di Windows per tale controllo specifico. A tale scopo, è necessario sostituire la routine nativa della finestra (WndProc) di un controllo nativo con una routine nativa della finestra generica, WindowProc, che esegua una ricerca per determinare se il controllo è incluso in un elenco di controlli associati ai metodi di callback da richiamare. Se la ricerca ha esito positivo, il controllo viene considerato associato.

Se il controllo è associato, WindowProc determina se è mappato in modo da rispondere a uno specifico messaggio di Windows. Questa è la cosiddetta mappa messaggi, che esegue il mapping di un messaggio di Windows a un delegato WndProcCallback che chiama il metodo gestito contenente la funzionalità desiderata. Se il messaggio è contenuto nella mappa messaggi, il delegato WndProcCallback richiama il codice utilizzando i parametri del messaggio forniti a WindowProc.

Associazione di controlli

Il metodo HookWndProc associa l'handle del controllo a una mappa messaggi che deve essere utilizzata dalla routine nativa della finestra generica WindowProc. Questa operazione è nota come associazione di un controllo.

Il metodo HookWndProc determina se un controllo è già stato associato. In caso negativo, crea un oggetto HookedProcInformation per il controllo. Questo oggetto contiene un riferimento al controllo e alla mappa messaggi. Se l'handle del controllo è già stato creato, la finestra viene associata creando un puntatore alla relativa routine nativa della finestra originaria per un ripristino successivo. Se invece l'handle non è stato creato, verrà associato dal metodo ctrl_HandleCreated che gestisce l'evento HandleCreated.

Successivamente il metodo HookWndProc aggiunge l'oggetto HookedProcInformation a uno dei due insieme di dizionari generici disponibili:

  • Il dizionario hwindDict, che contiene un elenco globale di tutti gli handle di finestra associati. La chiave è un elemento hwnd. I controlli di cui sono stati creati gli handle vengono inseriti in questo dizionario. I controlli contenuti in tale dizionario vengono valutati da WindowProc per qualsiasi messaggio mappato.

  • Il dizionario ctlDict , che contiene i controlli i cui handle non sono stati creati. Quando il metodo ctrl_HandleCreated viene chiamato, il controllo viene spostato nel dizionario hwndDict.

Dissociazione dei controlli

Con il metodo UnhookWndProc è possibile dissociare un controllo in due modi:

  • Rimuovere un messaggio dalla mappa messaggi relativa a un controllo continuando però a mantenere il controllo nel dizionario hwndDict delle finestra associate. Questo metodo inoltre ripristina la routine nativa della finestra originaria del controllo utilizzando un puntatore mantenuto nell'oggetto HookedProcInformation.

  • Rimuovere il controllo dal dizionario hwndDict dei controlli collegati, quindi rimuoverne l'handle e inserirlo nel dizionario ctrlDict oppure eliminare completamente il controllo. Questo metodo inoltre ripristina la routine nativa della finestra originaria del controllo utilizzando un handle mantenuto nell'oggetto HookedProcInformation.

La classe TreeViewBonus del programma di esempio, elencata in Procedura: creare una sottoclasse di TreeView tramite callback nativi, estende il controllo TreeView in modo da includere l'evento NodeMouseClick, che non è direttamente disponibile in .NET Compact Framework.

L'evento NodeMouseClick viene ottenuto aggiungendo il messaggio WM_NOTIFY alla mappa messaggi relativa al controllo, come avviene con la classe WndProcHooker. Il metodo di callback gestito WM_Notify_Handler richiama la funzione GetMessagePos nativa per ottenere le coordinate del cursore del mouse al momento dell'invio dei messaggi di Windows.

Queste coordinate sono relative all'area dello schermo visibile sul client e non al controllo TreeView. La classe TreeViewBonus converte le coordinate dello schermo in coordinate client con il metodo PointToClient per il controllo. Queste coordinate client vengono quindi inviate insieme al messaggio TVM_HITTEST per determinare se e dove è stato fatto clic sull'oggetto TreeViewBonus.

La classe TreeViewBonus contiene il codice per ottenere le coordinate relative al controllo utilizzando il messaggio TVM_HITTEST del controllo nativo.

Se il clic è stato fatto su uno dei nodi della visualizzazione struttura, la struttura TVHITTESTINFO nativa contiene l'handle di tale nodo. L'ultimo passaggio consiste nell'attraversare in modo ricorsivo i nodi TreeView gestiti, operazione eseguita dal metodo FindTreeNodeFromHandle, per individuare l'handle corrispondente e generare l'evento NodeMouseClick. La classe TreeNodeMouseClickEventArgs fornisce i seguenti dati:

  • Il nodo su cui è stato fatto clic.

  • Il pulsante su cui è stato fatto clic.

  • Il numero di clic, impostato su 1.

  • La coordinata X del punto in corrispondenza del quale è stato fatto il clic.

  • La coordinata Y del punto in corrispondenza del quale è stato fatto il clic.

La classe TreeViewBonus associa l'elemento padre del controllo TreeView nativo a una routine nativa della finestra gestita, come avviene con la classe WndProcHooker. Risponde all'evento OnParentChanged associando il controllo padre e adattandosi pertanto alla possibilità che il controllo TreeView sia stato spostato in un nuovo elemento padre, ad esempio da Form a Panel.

Le classi GradientFilledButton e GradientFill elencate in Procedura: creare una sottoclasse di Button tramite callback nativi estendono il controllo Button in modo da visualizzare un riempimento sfumato tra due colori. Questo programma ha come scopo principale quello di illustrare il processo di creazione delle sottoclassi. Esiste tuttavia un modo più semplice per visualizzare un riempimento sfumato in un pulsante, ovvero creando un controllo personalizzato derivato da Control, come descritto in Procedura: visualizzare un riempimento sfumato.

Il costruttore della classe GradientFilledButton crea istanze della classe WndProcHooker per eseguire il mapping di messaggi di Windows a callback gestiti. Questi metodi di callback disegnano il pulsante nello stato appropriato a seconda del messaggio di Windows e dello stato della proprietà Capture del controllo. Nella tabella riportata di seguito sono elencati i messaggi di Windows mappati e i rispettivi callback corrispondenti.

Messaggio di Windows

Metodo di callback gestito e descrizione

WM_KEYDOWN

WM_KeyDown_Handler: ridisegna il pulsante come selezionato se si preme la BARRA SPAZIATRICE o INVIO (tasto Azione).

WM_KEYUP

WM_KeyUp_Handler: ridisegna il pulsante come non selezionato e genera l'evento Click se il tasto premuto è la BARRA SPAZIATRICE o INVIO (tasto Azione).

WM_LBUTTONDOWN

WM_LeftButtonDown_Hander: ridisegna il pulsante come selezionato e imposta la proprietà Capture del mouse per il controllo su true.

WM_LBUTTONUP

WM_LButtonUp_Handler: ridisegna il pulsante come non selezionato, genera l'evento MouseUp se il cursore viene rilasciato all'interno dell'area client del controllo e imposta la proprietà Capture del mouse per il controllo su false.

WM_MOUSEMOVE

WM_MouseMove_Handler: ridisegna il pulsante se è stato selezionato in precedenza e la proprietà Capture è true.

WM_PAINT

WM_Paint_Handler: ridisegna il pulsante nello stato appropriato.

Questi metodi di callback gestiti utilizzano il metodo DrawButton per disegnare il pulsante nello stato appropriato. Questo metodo dispone di due overload per disegnare il pulsante in una finestra, come quella utilizzata in questo esempio, o in un oggetto Graphics. Entrambi gli overload accettano un valore booleano che corrisponde a true se il pulsante è stato selezionato.

La classe GradientFilledButton utilizza la classe GradientFill per eseguire le chiamate di richiamo piattaforma al codice nativo per effettuare il riempimento. La classe GradientFill fornisce le proprietà per impostare i colori iniziale e finale e specificare la direzione della sfumatura, ovvero da sinistra verso destra oppure dall'alto verso il basso.

Aggiunte alla community

Mostra: