Passa ai contenuti principali

Briciole di WPF: Finestre non rettangolari, WPF vs Windows Forms

Questa briciola vuole mettere in evidenza il completo supporto alla trasparenza presente in WPF.

Nel fare questo effettueremo un confronto con il supporto fornito nelle Windows Forms nella creazione di finestre non rettangolari.

Partiamo da WPF. Creare finestre non rettangolari in WPF è assolutamente banale. Prendiamo ad esempio il seguente XAML:

  1. <Window x:Class="MainWindow"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="MainWindow" Height="350" Width="525" Background="Transparent" WindowStyle="None" AllowsTransparency="True" MouseLeftButtonDown="Window_MouseLeftButtonDown">
  5.     <Canvas>
  6.         <Canvas.Background>
  7.             <ImageBrush ImageSource="./images/Drawing.png"></ImageBrush>
  8.         </Canvas.Background>
  9.         <Button Canvas.Top="91" Canvas.Left="100" Height="31" Width="70" Click="Button_Click">Premi</Button>
  10.         <TextBlock Canvas.Left="258" Canvas.Top="165" Height="30" Name="TextBlock1" Width="175" TextAlignment="Center" FontSize="20"/>
  11.     </Canvas>
  12. </Window>

L’immagine utilizzata come sfondo per il canvas principale è un’immagine con la trasparenza (nel nostro caso un png).
Per fare in modo che la Window supporti completamente la trasparenza è necessario:

  1. Impostare il backgroung della window a Trasparent: 
         Background="Transparent"
  2. Impostare lo stile della finestra senza i bordi e la caption:
         WindowStyle="None"
  3. Ed attivare la trasparenza:
         AllowsTransparency="True"

In particolare, se impostiamo la proprietà AllowsTransparency a true, è fondamentale impostare la proprietà WindowStyle a None, altrimenti otteniamo un errore in fase di esecuzione.

In questo modo, otteniamo una finestra con una forma non rettangolare, ma non abbiamo la possibilità di spostare la finestra, in quanto non è presente la caption.

Esempio di finestra non rettangolare

Per poter attivare lo spostamento della finestra cliccando su qualsiasi punto della finestra e trascinando la stessa è sufficiente scrivere il seguente codice come gestore dell’evento MouseLeftButtonDown:

  1. Private Sub Window_MouseLeftButtonDown(ByVal sender As System.Object, _
  2.                                        ByVal e As System.Windows.Input.MouseButtonEventArgs)
  3.     Me.DragMove()
  4. End Sub

Grazie ai routed events di WPF, la finestra viene spostata anche se ci posizioniamo con il mouse su qualsiasi controllo della nostra interfaccia che non gestisce il MouseLeftButtonDown. Nella solution che riporto nel download in fondo al post abbiamo un textblock e un button: possiamo spostare la finestra se clicchiamo sul textblock ma non sul bottone (quest’ultimo ha il gestore dell’evento click).

Vediamo, ora, come realizzare la stessa interfaccia con una windows forms. Le tecniche che si possono utilizzare per realizzare una form non rettangolare con Windows Forms sono sostanzialmente due: disegnando tramite le classi Drawing la region dell’interfaccia grafica nel metodo OnPaint della finestra  oppure, più semplicemente, impostando nel seguente modo le proprietà della finestra:

  1. Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  2.     Me.BackgroundImage = New Bitmap(My.Resources.Drawing, New Size(Me.Width, Me.Height))
  3.     Me.FormBorderStyle = FormBorderStyle.None
  4.     Me.TransparencyKey = Color.FromArgb(0, 255, 255)
  5. End Sub

In questo caso la nostra immagine è presente nelle risorse del progetto (ma potrebbe essere letta anche da file) ed ha un colore scelto da noi (celeste (0,255,255) in questo caso) per indicare la parte di finestra trasparente.

Il risultato è una finestra di questo tipo:

Windows Forms non rettangolareIl problema nasce quando vogliamo abilitare il trascinamento della finestra da parte dell’utente. In questo caso dobbiamo simulare ciò che accade quando è presente la caption e l’utente è in grado di cliccare con il mouse al di sopra della stessa e trascinare l’intera finestra tenendo premuto il tasto sinistro del mouse.

Per fare questo dobbiamo utilizzare P/Invoke ed importare le seguenti funzioni:

  1. <DllImport("user32.dll")> _
  2. Private Shared Function SendMessage( _
  3.                 ByVal hWnd As IntPtr, _
  4.                 ByVal Msg As UInteger, _
  5.                 ByVal wParam As IntPtr, _
  6.                 ByVal lParam As IntPtr) As IntPtr
  7. End Function
  8.  
  9. <DllImport("user32.dll")> _
  10. Private Shared Function ReleaseCapture() As Boolean
  11. End Function
  12.  
  13. Const WM_NCLBUTTONDOWN As UInteger = &HA1
  14. Const HTCAPTION As Integer = 2

Potete trovare maggiori riferimenti alle API utilizzate ai seguenti link: SendMessage e ReleaseCapture.

Utilizziamo queste API contenute nella user32.dll per simulare le azioni che esegue l’utente al di sopra della caption della finestra nel momento in cui decide di spostarla:

  1. Private Sub MoveWindow()
  2.     Dim lngReturnValue As IntPtr
  3.     Call ReleaseCapture()
  4.     lngReturnValue = SendMessage(Me.Handle, WM_NCLBUTTONDOWN, New IntPtr(HTCAPTION), New IntPtr(0))
  5. End Sub

Utilizziamo questa funzione all’interno del gestore di evento mousemove della form e di tutti i controlli che non hanno interazione diretta con l’utente (nel nostro caso la label).

  1. Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
  2.             Handles Me.MouseMove
  3.     If e.Button = System.Windows.Forms.MouseButtons.Left Then
  4.         MoveWindow()
  5.     End If
  6. End Sub
  7.  
  8. Private Sub TextBlock1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
  9.             Handles TextBlock1.MouseMove
  10.     If e.Button = System.Windows.Forms.MouseButtons.Left Then
  11.         MoveWindow()
  12.     End If
  13. End Sub

In definitiva possiamo osservare che, per sua natura intrinseca WPF ci consente di realizzare la form non rettangolare agendo semplicemente nello XAML e sfruttando le caratteristiche di trasparenza dei formati grafici, inoltre ci semplifica la vita nella gestione del drag and drop della finestra non costringendoci all’utilizzo di P/Invoke (che tra le altre cose rende l’applicazione poco portabile).

Commenti

Post popolari in questo blog

VB.NET: Convertire un file DOC in RTF e PDF con office interop

In questo post vorrei proporvi del codice per poter convertire un file .doc in un file .rtf oppure .pdf utilizzando le API di interoperabilità di Office.Creeremo una classe, DocConverter, che esporrà le due funzionalità sopra citate.Cominciamo con il prevedere un attributo privato della classe che rappresenterà l’applicazione Word che utilizzeremo per la conversione. Creeremo l’istanza dell’attributo privato all’interno del costruttore della classe:PublicSubNew()
IfNot CreateWordApp() Then
ThrowNew ApplicationException("Assembly di interoperabilità con Office non trovato!")
EndIf
EndSub
Private _wordApp As Word.ApplicationClass
ProtectedFunction CreateWordApp() AsBoolean
Dim retval = True
Try
_wordApp = New Word.ApplicationClass()
_wordApp.Visible = False
Catch ex As System.Exception
_wordApp = Nothing
retval = False
EndTry
Return retval
EndFunction

La conversione del file doc sarà effettuata aprendo il file stesso ed eseguendo un’operazione di SaveAs:

Pr…

Cambiare la lingua di Visual Studio 2008

Oggi ho avuto qualche problema installando Windows Mobile 6 Professional SDK Refresh e Windows Mobile 6 Standard SDK Refresh.Scaricati i file di installazione e installati, ho provato a creare un progetto di tipo Windows Mobile 6.0 e mi sono beccato questo errore:Dopo qualche smanettamento abbiamo scoperto (e ringrazio il mitico Matteo per l’aiuto) che il mio Visual Studio 2008, pur essendo in Inglese (prova ne era il fatto che gli hotfix e la SP installata erano nella lingua di Albione) aveva come lingua impostata quella del sistema operativo (italiano).Ovviamente, non avrebbe mai potuto trovare la cartella 1040 (italiano) visto che l’installazione dell’SDK aveva supposto che la lingua del Visual Studio fosse Inglese (1033).La soluzione del problema è duplice:1) Duplicate la cartella 1033 presente nel percorso evidenziato dall’errore e la rinominate 10402) cambiate la lingua di Visual Studio.Per questa ultima eventualità basta andare nel menù Strumenti/Opzioni:e cambiare il linguaggi…

Tascam DR-05 registratore digitale per tutti

Diverso tempo fa ho acquistato il registratore digitale Tascam DR-05 e, ora, dopo diversi mesi di utilizzo, posso dire la mia a proposito.

Si tratta di un ottimo registratore digitale con microfono stereo che permette di ottenere registrazioni di ottima qualitaà anche in ambienti non perfetti dal punto di vista acustico.

Interessante la possibilità di utilizzare un cavalletto di piccole dimensioni come HAMA Mini treppiede o Mini Cavalletto Universale per tenere il microfono sollevato dal tavolo in fase di registrazione grazie allàattacco universale per macchina fotografica che il microfono ha nella parte inferiore.

Da segnalare anche il menu’ ben fatto e la possibilita’ di utilizzare una scheda SD esterna per memorizzare i file audio. Anche a livello di consumo batterie non e’ niente male. Consiglio l’uso delle alcaline non ricaricabili.

Il mio utilizzo e’ stato prettamente di registrazione di podcast vocali (no musica) ma le recensioni confermano che se la cava egregiamente con la mu…