Your Ad Here

martedì 9 febbraio 2010

Rilasciato Visual Studio 2010 RC per gli abbonati MSDN

Brian Harry (inchino ) ha annunciato (qui il post) il rilascio della versione RC di Visual Studio 2010 per gli abbonati MSDN. Da mercoledì prossimo dovrebbe essere disponibile per tutti.

domenica 7 febbraio 2010

Software per ipovedenti gratuito

Vi segnalo una notizia apparsa sul sito di DotNetRomaCestà:

http://www.dotnetromacesta.org/Notizie.aspx?IdNews=106

Si tratta della nuova versione di Vivo 3 portatile, un programma unico ed in italiano che far parlare il computer, molto utile per le persone che hanno difficoltà di lettura.

Si tratta di un programma che non necessita di installazione. E, poi, è italiano!!!

Accessorio di SnagIT per Team System

Vorrei segnalarvi il seguente accessorio per SnagIT che permette di catturare un’immagine dallo schermo (come fa normalmente SnagIT) e di inserirla all’interno di Visual Studio Team System.

Maggiori indicazioni sulla pagina di download dell’accessorio:

http://www.techsmith.com/snagit/accessories/teamsystem.asp

o nella guida PDF scaricabile dalla stessa pagina.

Interessante post di Lorenzo Barbieri sul Blog MSDN

Vorrei segnalarvi un interessante post di Lorenzo Barbieri sul Blog MSDN relativo allo stato dell’arte dell’ALM:

http://blogs.msdn.com/italy/archive/2010/02/05/riflessioni-sui-trend-nei-sistemi-di-gestione-del-codice-sorgente.aspx

Decisamente interessante.

giovedì 4 febbraio 2010

Briciole di WPF : Le risorse incorporate

In WPF, come accade in Windows Form, possiamo incorporare delle risorse (immagini, file sonori, video, etc, etc.) all’interno di un assembly.

La modalità con cui eseguiamo questa operazione è però più vicina al mondo web che non al mondo delle Windows Forms. Per poter inserire un file di risorse all’interno di un nostro assembly è sufficiente creare una o più cartelle all’interno del progetto e, quindi, inserirvi i file da includere come risorse. Per finire è sufficiente che tali file abbiamo la proprietà Build Action impostata su Resource.

Ad esempio, nel seguente progetto abbiamo incorporato 6 immagini e un file audio:

Progetto con risorse incorporate

Nelle Windows Forms, invece, incorporiamo le risorse aggiungendole al file Resources.resx.

Nel caso precedente, nel momento in cui compiliamo, le risorse vengono inserite nell’assembly come stream di byte. Per verificare questo, possiamo aprire l’assembly con le risorse tramite Reflector:
 Le risorse incorporateOsserviamo la presenza di un oggetto memory stream per ogni file di risorsa incorporato. 

Per poter estrarre ed utilizzare le risorse all’interno del nostro codice abbiamo due strade.

La più complessa è quella di creare degli oggetti di classe UnmanagedMemoryStream come nel seguente pezzo di codice in cui estraiamo lo stream relativo alla risorsa “smile.png”:

  1. Dim imageStream As UnmanagedMemoryStream
  2. Dim resourceName = "AssemblyResource.g"
  3. Dim rm As New ResourceManager(resourceName, asm)
  4. Using resSet = rm.GetResourceSet(CultureInfo.CurrentCulture, True, True)
  5.     Dim obj = resSet.GetObject("images/smile.png", True)
  6.     imageStream = CType(obj, UnmanagedMemoryStream)
  7. End Using

Questa modalità è simile a quella che si ottiene utilizzando il metodo GetManifestResourceStream() e, come questa, nasconde la difficoltà di utilizzare uno stream di dati.

Fortunatamente WPF ci mette a disposizione un metodo molto più semplice per referenziare delle risorse incorporate, un metodo che sa molto di web.

A livello di XAML basta scrivere:

  1. <Image Source="images/smile.png"></Image>

Quindi la nostra risorsa è recuperabile con un URI (di tipo relativo) sullo stile delle immagini dei siti web.

Il meccanismo precedente è utilizzabile anche per le risorse presenti in un assembly esterno. In questo caso la sintassi è del tipo:

  1.  
  2. <Image Source="ResourceLib;component/images/sun.png" />

Anche dal punto di vista del code behind di WPF, possiamo impostare la proprietà Source di un controllo image tramite un URI:

  1. Me.Image.Source = New BitmapImage(
  2.                         New Uri("images/smile.png",
  3.                                 UriKind.Relative))

In download potete trovare una semplice solution di Visual Studio 2010 in cui mostro come effettuare il caricamento di un’immagine da una serie di risorse utilizzando l’uri:

Applicazione WPF con le risorse incorporate

lunedì 1 febbraio 2010

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).

venerdì 29 gennaio 2010

Briciole di WPF: Ma quanti colori vuoi?!?!?

Questa briciola è dedicata alla structure Color presente nel namespace System.Windows.Media.

Di fatto si tratta della nuova struttura di colore introdotta da WPF che viene utilizzata dal presentation framework al posto della vecchia Color del namespace System.Drawing.

Ci sono due grandi differenze “esteriori” tra le due strutture.

La prima differenza è che la vecchia struttura può rappresentare 16.777.216 di colori essendo le sue componenti RGB rappresentate da 1 Byte ciascuno (256 possibili valori). Ogni terna di valori RGB ha, inoltre, 256 possibili valori di trasparenza.

La nuova struttura, invece, ha anche la possibilità di esprimere le componenti RGB (e Alfa) con dei valori di tipo Single (solo positivi o nulli) e, quindi, in linea teorica con un range di colori molto più ampio. La nuova struttura nasce con lo scopo di supportare lo standard scRGB (wiki docet).

La struttura Color di WPF mette ancora a disposizione dello sviluppatore le proprietà (A, R, G, B) che riportano il singolo canale espresso con un byte, ma forniscono anche delle proprietà (ScA, ScR, ScG, ScB) che esprimono le componenti del colore con dei valori di tipo Single.

I due insiemi di proprietà sono tra loro sincronizzati nel senso che se impostiamo uno dei canali “vecchi” otteniamo che il corrispondente canale “nuovo” ha il proprio valore aggiornato (con un valore tra 0 e 1. La conversione in questo verso avviene con una funzione di normalizzazione che possiamo ricavare utilizzando Reflector:

  1. Private Shared Function sRgbToScRgb(ByVal bval As Byte) As Single
  2.     Dim num As Single = (CSng(bval) / 255.0!)
  3.     If (num <= 0) Then
  4.         Return 0.0!
  5.     End If
  6.     If (num <= 0.04045) Then
  7.         Return (num / 12.92!)
  8.     End If
  9.     If (num < 1.0!) Then
  10.         Return CSng(Math.Pow(((num + 0.055) / 1.055), 2.4))
  11.     End If
  12.     Return 1.0!
  13. End Function

dove bval è il valore del canale “vecchio” e il ritorno della funzione è il valore del canale “nuovo”.

Quando impostiamo, invece, una delle proprietà dei nuovi canali, anche le corrispettive proprietà dei vecchi canali vengono aggiornate. Stavolta la funzione utilizzata per l’aggiornamento è la seguente:

  1. Private Shared Function ScRgbTosRgb(ByVal val As Single) As Byte
  2.     If (val <= 0) Then
  3.         Return 0
  4.     End If
  5.     If (val <= 0.0031308) Then
  6.         Return CByte((((255.0! * val) * 12.92!) + 0.5!))
  7.     End If
  8.     If (val < 1) Then
  9.         Return CByte(((255.0! * ((1.055! * CSng(Math.Pow(CDbl(val), 0.41666666666666669))) - 0.055!)) + 0.5!))
  10.     End If
  11.     Return 255
  12. End Function

In questo caso val è il valore del “nuovo” canale, mentre il ritorno della funzione è il valore del “vecchio” canale.

Altra differenza tra la nuova Color e la vecchia è che nella prima sono state rimosse le proprietà statiche che definivano i cosiddetti “colori noti” (ad esempio Color.Red). E’ stata, in questo senso, creata una nuova classe (interamente costituita da proprietà statiche ) Colors che contiene queste definizioni.

Se apriamo con Reflector la nuova structure Color osserviamo che anche il modo con cui internamente sono memorizzati i canali è cambiato.

Nella Color del namespace Drawing i canali sono memorizzati in un unico oggetto di tipo In64, mentre nella nuova structure abbiamo due strutture private ognuna delle quali ha 4 attributi (single o byte) che identificano i canali.

lunedì 25 gennaio 2010

Briciole di WPF : InkCanvas e gesture

In questo post vorrei farvi vedere come poter riconoscere le gesture (cioè i movimenti) che l’utente può fare con il mouse, con le dita o con un eventuale stilo utilizzando il contenitore InkCanvas.

Il controllo InkCanvas, in realtà, si può utilizzare per intercettare i “gesti” dell’utente, per disegnare, per selezionare una porzione di interfaccia o per tutte queste funzionalità contemporaneamente.

Cominciamo col dire che per poter utilizzare l’InkCanvas solo per intercettare le gesture dell’utente è necessario impostare la proprietà EditingMode con il valore InkCanvasEditingMode.GestureOnly.

L’enumerazione InkCanvasEditingMode contiene tutti i possibili comportamenti dell’InkCanvas:

  • GestureOnly : il controllo rileva le gesture. In questo caso l’utente lascia un segno sulla superficie del controllo ma questo sparisce al termine della singola gesture;
  • EraseByPoint : permette di cancellare una parte di un precedente disegno passando il pennino come una gomma;
  • EraseByStroke : permette di cancellare un’intera curva precedentemente disegnata passando il pennino come una gomma;
  • Ink : l’utente può disegnare con il pennino;
  • InkAndGesture : l’utente può disegnare ma il controllo rileva anche le gesture;
  • None : il controllo non permette di disegnare e non rileva le gesture;
  • Select : il controllo permette di selezionare una porzione della superficie del controllo.

Concentriamoci, ora su come possiamo intercettare le gesture dell’utente.

Per poter far si che il controllo InkCanvas sia in grado di intercettare le gesture dobbiamo, inizialmente impostare la sopra citata proprietà, quindi istruire il controllo stesso su quali gesture siamo intenzionati ad intercettare.

Per fare questa ultima operazione dobbiamo utilizzare il metodo SetEnabledGestures che si aspetta come argomento un oggetto IEnumerable(of ApplicationGesture).

Ad esempio potremmo scrivere:

  1. Dim gestures = {ApplicationGesture.Circle,
  2.                 ApplicationGesture.Square,
  3.                 ApplicationGesture.Triangle}
  4. inkCanvas.SetEnabledGestures(gestures)

per istruire il controllo a rilevare i cerchi, i quadrati e i triangoli descritti dall’utente. Attenzione che, se non eseguiamo il metodo SetEnabledGestures

Istruito il controllo dobbiamo preoccuparci di gestire l’evento Gesture che è l’evento scatenato dal controllo ogni qual volta l’utente appoggia, muove e rilascia il pennino sulla superficie del controllo.
Dobbiamo subito precisare che tale evento viene scatenato sempre, per qualsiasi gesture dell’utente (anche se non è una di quelle per cui abbiamo istruito il controllo).

L’evento Gesture mette a disposizione, come argomento un oggetto di tipo InkCanvasGestureEventArgs, derivato da RoutedEventArgs, dal quale possiamo ricavare o l’insiame delle linee disegnate dall’utente (tramite la proprietà Strokes) oppure far riconoscere al framework quali sono state le gesture che l’utente ha tentato di eseguire.

Il primo caso è da utilizzare quando vogliamo interpretare, con un nostro algoritmo, le gesture dell’utente; il secondo caso, invece, delega al framework il riconoscimento rendendoci la vita più semplice.

Per recuperare l’elenco delle gesture interpretate dal framework possiamo utilizzare il metodo GetGestureRecognitionResults() della classe InkCanvasGestureEventArgs.
Questo metodo restituisce una collezione (sola lettura) di oggetti GestureRecognitionResult.

La classe GestureRecognitionResult contiene le informazioni relative alle gesture, ed in particolare possiamo utilizzare le due proprietà RecognitionConfidence e ApplicationGesture per capire esattamente quale gesture sono state eseguite dall’utente.

RecognitionConfidence è un enumerazione che può assumere i seguenti valori Poor, Intermediate e Strong ed indica la “precisione” con cui il framework ha interpretato la gesture.

ApplicationGesture, infine, contiene la gesture riconosciuta (se è una di quelle per cui il controllo è stato istruito) oppure NoGesture se la gesture non è riconosciuta.

Per testare il meccanismo di riconoscimento delle gesture ho preparato una semplice applicazione WPF che contiene un InkCanvas, un elenco di checkbox per selezionare le gesture da riconoscere, un livello minimo di riconoscimento delle gesture e un’area (costituita da un TextBlock) in cui verrà scritta la gesture eventualmente riconosciuta.

Il layout dell’applicazione è il seguente:

Layout_Applicazione_GestureIn questa window possiamo selezionare per quali gesture “istruire” l’InkCanvas e quale è il livello minimo desiderato di precisione della gesture.

In particolare, nel momento in cui selezioniamo (o deselezioniamo) una delle gesture mostrate nella lista di destra, viene richiamato il seguente codice:

  1. Private Sub AddApplicationGestures()
  2.     Me.inkCanvas.EditingMode = InkCanvasEditingMode.GestureOnly
  3.  
  4.     Dim gestures = (From c In Me.pnlGestureOptions.Children.OfType(Of Control)()
  5.                     Where TypeOf (c) Is CheckBox AndAlso CType(c, CheckBox).IsChecked
  6.                     Select CType(c.Tag, ApplicationGesture)).ToList()
  7.  
  8.     If gestures.Count = 0 Then
  9.         gestures.Add(ApplicationGesture.NoGesture)
  10.     End If
  11.     Me.inkCanvas.SetEnabledGestures(gestures)
  12.  
  13. End Sub

Il precedente metodo ricava i valori delle gestures dei CheckBox selezionati nel pannello di destra tramite una query LINQ e utilizza il metodo SetEnableGestures() per impostarli sul controllo InkCanvas. Se nessun CheckBox è selezionato (nessuna gesture) allora viene impostato il valore “NoGesture”.

Quando l’utente disegna una linea nell’InkCanvas, il controllo genera l’evento Gesture nel quale andiamo a verificare che l’utente abbia disegnato una delle gesture da noi selezionate:

  1. Private Sub inkCanvas_Gesture(ByVal sender As System.Object, ByVal e As System.Windows.Controls.InkCanvasGestureEventArgs)
  2.     Dim gestureResults As ReadOnlyCollection(Of GestureRecognitionResult)
  3.     gestureResults = e.GetGestureRecognitionResults()
  4.  
  5.     For Each gesture In gestureResults
  6.         If gesture.ApplicationGesture <> ApplicationGesture.NoGesture Then
  7.             If optPoor.IsChecked And gesture.RecognitionConfidence = RecognitionConfidence.Poor Then
  8.                 Me.txtResult.Background = New SolidColorBrush(Color.FromRgb(0, 255, 255))
  9.                 Me.txtResult.Text = gesture.ApplicationGesture.ToString()
  10.                 Exit For
  11.             End If
  12.             If optIntermediate.IsChecked And gesture.RecognitionConfidence = RecognitionConfidence.Intermediate Then
  13.                 Me.txtResult.Background = New SolidColorBrush(Color.FromRgb(255, 255, 255))
  14.                 Me.txtResult.Text = gesture.ApplicationGesture.ToString()
  15.                 Exit For
  16.             End If
  17.             If optStrong.IsChecked And gesture.RecognitionConfidence = RecognitionConfidence.Strong Then
  18.                 Me.txtResult.Background = New SolidColorBrush(Color.FromRgb(0, 255, 0))
  19.                 Me.txtResult.Text = gesture.ApplicationGesture.ToString()
  20.                 Exit For
  21.             End If
  22.         Else
  23.             Me.txtResult.Background = New SolidColorBrush(Color.FromRgb(255, 0, 0))
  24.             Me.txtResult.Text = gesture.ApplicationGesture.ToString()
  25.         End If
  26.     Next
  27. End Sub

Se la gesture è riconosciuta (ed ha, al minimo, il livello di precisione da noi selezionato) viene visualizzato il relativo valore con un opportuno colore (in base alla precisione), altrimenti viene visualizzato NoGesture.

L’applicazione mostrata è molto semplice ed inutile, ma può mostrare come interagire con l’InkCanvas per eseguire operazioni quando l’utente esegue particolari gesture.

Per scaricare i sorgenti della soluzione di prova (Visual Studio 2010) cliccare sull’icona seguente:

giovedì 21 gennaio 2010

Briciole di WPF : Single instance application (soluzione 2).

Nel precedente post abbiamo visto una soluzione al problema della mancanza della possibilità di avviare un’applicazione WPF come singola istanza.

In questo post vorrei proporvi un’altra soluzione al problema che si basa sull’utilizzo della classe Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase che espone dei metodi per la gestione di un’applicazione Windows Form.

Il concetto di fondo è quello di sostituire, per la gestione del ciclo di vita dell’applicazione WPF, la classe Application con la classe WindowsFormsApplicationBase, o per meglio dire con una sua derivata.

Creiamo la classe:

  1. Public Class SingleInstanceApplication
  2.     Inherits Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
  3.  
  4.     Friend Sub New()
  5.         Me.IsSingleInstance = True
  6.     End Sub
  7.  
  8.     Private _app As WPFApplication.Application
  9.  
  10.     Protected Overrides Function OnStartup(ByVal eventArgs As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) As Boolean
  11.         _app = New WPFApplication.Application()
  12.         _app.StartupUri = New Uri("MainWindow.xaml", UriKind.Relative)
  13.         _app.Run()
  14.         Return False
  15.     End Function
  16.  
  17.     Protected Overrides Sub OnStartupNextInstance(ByVal eventArgs As Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs)
  18.         Me.OnShutdown()
  19.     End Sub
  20.  
  21. End Class

Dove WPFApplication.Application è la nostra classe applicazione WPF (il code behind del file Application.xaml) e MainWindow.xaml è la finestra principale dell’applicazione.

Se riusciamo a far partire la classe SingleInstanceApplication all’avvio dell’applicazione WPF, allora siamo in grado di gestire lo Startup e lo StartupNextInstance e gestire, in questo modo l’avvio di più istanze della nostra applicazione.

Per risolvere questo ultimo problema costruiamo una classe di Startup:

  1. Public Class Startup
  2.     Public Shared Sub Main(ByVal args As String())
  3.         Dim singleInstance = New SingleInstanceApplication()
  4.         singleInstance.Run(args)
  5.     End Sub
  6. End Class

e modifichiamo le proprietà dell’applicazione WPF per far eseguire la classe Startup all’avvio. Per fare questo è sufficiente:

  1. Aprire la pagina delle proprietà dell’applicazione WPF cliccando con il tasto destro del mouse sul progetto e scegliendo il menù Proprietà;
  2. Disattivare il checkbox per l’attivazione dell’application framework;
  3. Selezionare la classe Startup come oggetto di avvio.

WPF_Application_Property In questo modo, nel momento in cui l’applicazione viene avviata la prima volta, viene eseguito il metodo OnStartup della classe SingleInstanceApplication e, tutte le volte che viene eseguita un’ulteriore istanza dell’applicazione (senza aver chiuso la prima) il metodo OnStartupNextInstance.

Questi due metodi, in particolare il secondo, ci consentono di decidere cosa fare dalla seconda istanza in poi. Inoltre, la classe SingleInstanceApplication è unica, possiamo gestire quei scenari in cui il lancio di una successiva istanza dell’applicazione deve far aprire una finestra figlia dell’applicazione principale (ad esempio un nuovo documento di word).

Tramite l’attributo _app della classe SingleInstanceApplication possiamo, infatti, interagire con l’applicazione in esecuzione.

Nell’esempio che trovate allegato ho realizzato un’applicazione che conta il numero di istanze che l’utente tenta di avviare successivamente alla prima.

Download sorgenti :

mercoledì 20 gennaio 2010

Quanti PC nel mondo hanno “a bordo” il framework?

Vi vorrei citare un post di Scott Hanselman in cui vengono dati dei numeri riguardo la diffusione nel mondo del framework .NET:

Scott Hanselman's Computer Zen - How many PCs in the world have the .NET Framework installed?

I numeri sono decisamente interessanti ma c’è da dire, però, che su Vista e Windows 7, c’è già la versione del framework “di serie”.

Technorati Tag: