Ho deciso di pubblicare un avviso per comunicare che tutta la mia produzione sarà resa disponibile principalmente (in tempo reale) nella pagina https://www.patreon.com/garage40, mentre su YouTube e altri canali il materiale sarà pubblicato ad alcune settimane di distanza… video per i dettagli.
Categoria: Tips
Suggerimenti e trucchi di programmazione
Books and articles in English
For at least 15 years now, I have published at least 50 articles and 16 books on technical subjects: programming, databases, electronics (with Arduino), Office and so on.
So far, I have only published in Italian, but I feel the need to expand my horizons, so I am going to do an experiment: I will try to translate some of my articles from Italian into English. I will also try to translate my next posts in this blog.
I would appreciate it if you could point out any grammatical errors (or nonsense sentences) so that I can improve my translations.
Thank you!
Un po’ di somme del 2018 e buoni propositi del 2019…
Approssimandosi la fine del 2018 bisogna tirare le somme e darsi dei nuovi obiettivi. Il 2018, come gli ultimi anni, dal punto di vista di uno “scrittore tecnico” non è stato granché:
-
rilevo sempre di più un “abbandono” dei libri cartacei, aggravato dal fatto che i prodotti software si aggiornano sempre più velocemente: quando un libro tecnico è pronto, è già vecchio perché è uscita una nuova versione (o anche “n” aggiornamenti della stessa versione)
-
le riviste di programmazione italiane non esistono più. Regge ancora l’ambito dell’elettronica, dove riviste come “Elettronica In” lavorano ancora, ma il mio primo esperimento di articolo “misto elettronica+sviluppo in Visual Studio” è stato consegnato a fine settembre e non è ancora stato pubblicato;
-
le applicazioni (a pagamento) dallo Store di Microsoft per Windows 10 non hanno un così grande ritorno da essere convenienti. Ho tentato anche di creare una sorta di “libro digitale” in un’applicazione MS Store per Windows 10, ma i numeri sono veramente piccoli piccoli.
Vedo però che continuo a ricevere e-mail di apprezzamento per i libri e articoli che ho scritto in passato e, spesso, anche richieste di altri articoli e libri e quindi non voglio lasciare insoddisfatte queste richieste.
Dal 1° gennaio 2019 in poi, quindi, mi preparerò per una nuova modalità di distribuzione dei miei testi (articoli e/o libri), oltre che attraverso il solito canale dei libri autoprodotti con Amazon: si tratta del canale offerto dal sito http://www.sfogliami.it: con questo sito potrò pubblicare i testi in formato digitale e questi saranno fruibili sfogliandoli direttamente sullo schermo, come uno dei tanti quotidiani e notiziari che ormai hanno scelto questa forma di pubblicazione.
Con l’acquisto di un testo offrirò anche la possibilità di scaricare il testo stesso in formato digitale, in modo da poterlo fruire in qualunque modo voi desideriate (PC, tablet, smartphone o anche cartaceo se volete stamparvelo).
Per ciascun testo (articolo o libro) fisserò un prezzo proporzionale ai contenuti (lunghezza e complessità), ma limitandolo al minimo, visto che non ci sono particolari costi da affrontare (non ci sono costi di carta, stampa, distribuzione, del revisore, del grafico, del tipografo ecc. ecc.).
Sperando di incontrare così i vostri gusti e il vostro interesse, colgo l’occasione di questo post per augurare a tutti voi
B U O N 2 0 1 9 !!!
#4 Ottenere l’indirizzo IP [== AGGIORNATO ==]
Questo era un post che avevo pubblicato in questo blog ben 10 anni fa e ora lo riprendo perché è opportuno che venga modificato qualcosa…
In particolare il metodo Dns.GetHostByName() è deprecato e quindi bisogna utilizzare un codice diverso. Quello che vi consiglio io è questo:
Private Function GetIPv4Address() As String
GetIPv4Address = String.Empty
Dim strHostName As String = System.Net.Dns.GetHostName()
Dim iphe As System.Net.IPHostEntry =
System.Net.Dns.GetHostEntry(strHostName)
For Each ipheal As System.Net.IPAddress In iphe.AddressList
If ipheal.AddressFamily =
System.Net.Sockets.AddressFamily.InterNetwork Then
GetIPv4Address = ipheal.ToString()
If GetIPv4Address.Substring(0, 7) = "192.168" Then
Return GetIPv4Address
End If
End If
Next
End Function
Ho sperimentato vari metodi, ma l’unico che ho trovato che permetta di estrarre un indirizzo IPv4 (in particolare l’indirizzo locale 192.168.xxx.xxx) è quello di questa variante.
Se togliete il test sulla stringa “192.168“ è probabile che invece vi venga presentato l’indirizzo IP che il router ADSL ha sulla rete esterna.
[VECCHIO TESTO]:
Per ottenere l’indirizzo IP della macchina (collegata in rete) sulla quale gira il programma, ecco una soluzione valida per Visual Basic 2005:
Private Shared Sub NamedSub() Dim loip() As System.Net.IPAddress = _ System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName) Dim ip As String = loip(0).ToString MessageBox.Show(ip) End Sub
E’ possibile ottenere altre informazioni sulla connessione di rete leggendo questo articolo pubblicato su MSDN
Il metodo usato in Visual Basic 2003 è obsoleto e da evitare:
Dim ip As String = _ System.Net.Dns.GetHostByName(System.Net.Dns.GetHostName) .AddressList(0).ToString
N.B.: l’istruzione deve essere scritta tutta su una singola riga
#56 – [VB.NET] Verificare lo stato della coda di stampa predefinita
Se avete la necessità di verificare lo stato della coda di stampa predefinita, potete utilizzare il namespace System.Printing che trovate però solo dal Framework .NET 3.0 in poi.
Per prima cosa dovete aggiungere un riferimento a System.Printing nella scheda Riferimenti delle proprietà del progetto.
Una volta aggiunto il riferimento, utilizzate un codice simile a questo:
Imports System.Printing Public Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click Dim ps As New LocalPrintServer() Dim pq As PrintQueue = ps.DefaultPrintQueue Dim err As Boolean = pq.IsInError If err = True Then MessageBox.Show("Errore di stampante") Else MessageBox.Show("Nessun errore di stampante") End If End Sub End Class
#55: [VB.NET] Misurare il tempo di esecuzione
…Spesso ci capita di conoscere varie tecniche per risolvere un nostro problema applicativo e/o di programmazione e non sappiamo quali di queste tecniche è più efficace dal punto di vista delle prestazioni, cioè quale impiega meno tempo a terminare l’esecuzione.
Le prestazioni di diversi algoritmi, talvolta, hanno una piccola differenza di tempo nell’esecuzione di singoli passi di programma, ma se moltiplichiamo la differenza di tempo per centinaia di migliaia di elementi da elaborare, il tempo totale diventa percepibile in modo pesante dall’utente. E’ quindi necessario sperimentare i vari algoritmi o frammenti di codice per verificare quale sia preferibile tra le varie possibilità.
Un modo semplice è quello di utilizzare un oggetto di classe TimeSpan, rilevando i “ticks” all’inizio del frammento di codice e alla fine del frammento, calcolando poi la differenza tra le due registrazioni.
I “tick” sono le più piccole unità di tempo in .NET, equivalenti a 100 nanosecondi.
Per esempio:
... ‘ prima registrazione
Dim ts1 As New TimeSpan(Now.Ticks)
‘ frammento di codice o ciclo da valutare
...
‘ registrazione finale e visualizzazione della differenza di tempo
Dim ts2 As New TimeSpan(Now.Ticks)
MessageBox.Show((ts2 - ts1).ToString)
...In questo modo sarà possibile esaminare i tempi di diversi algoritmi ed effettuare così la scelta del migliore, nel caso preso in esame.
Attenzione: non è un metodo che permette di effettuare dei veri e propri benchmark, perché i tempi di esecuzione spesso dipendono da molti altri fattori. Per esempio servizi e programmi attivi, disponibilità di RAM nel momento dell’esecuzione, carico del processore e così via. In ogni caso, il metodo proposto è un metodo empirico sufficientemente significativo e soprattutto semplice per fare delle valutazioni “a spanne” ma con dei dati alla mano. Per un migliore risultato e una maggiore sicurezza delle misurazioni è consigliabile ripetere la misurazione più volte.
#47: VB.NET – ADO.NET 2.0 – Supporto a Vista 64 bit e Access 2007
Prendendo spunto da una discussione nel forum dedicato a VB & .NET (http://www.visual-basic.it/forum/thread.asp?m=163649) della Community Visual Basic Tips & Tricks (www.visual-basic.it), ma anche da un mio problema personale proprio su questo argomento, ho pensato che fosse opportuno fissare un paio di appunti e di precisazioni, in particolare sull’uso del Provider JET 4.0 per l’accesso ai database in formato Access 2007 e sul problema del sistema operativo Windows Vista a 64 bit.
Partiamo dal caso dei 64 bit. Come molti sapranno, Vista è distribuito in due edizioni: a 32 bit, che è la piattaforma che molti di noi sono abituati ad utilizzare da molto tempo, e a 64 bit. Prossimamente, le nuove versioni di Windows arriveranno esclusivamente a 64 bit e quindi ci dobbiamo abituare a convivere con questa nuova piattaforma, con le sue particolarità.
Il problema deriva dal fatto che Windows Vista a 64 bit non supporta JET 4.0, in quanto questo provider dati è fornito solo a 32 bit.
Le alternative per risolvere questo problema sono sostanzialmente due:
- evitare di utilizzare Access e orientarsi direttamente all’uso di SQL Server Express, Compact o edizioni superiori (consigliato!);
- compilare il progetto Visual Basic 2008 o Visual C# 2008 con il solo supporto per la piattaforma x86 (cioè a 32 bit).
Per questa seconda possibilità, dobbiamo eseguire i seguenti passi:
- fare click con il pulsante destro del mouse sul nome del progetto e scegliere “Proprietà”;
- passare alla scheda “Compilazione”;
- fare click sul pulsante “Opzioni di compilazione avanzate”;
- nella combo “CPU di destinazione” selezionare “x86”, anziché “AnyCPU”.
A questo punto potremo eseguire l’applicazione anche su Vista a 64 bit, tenendo però conto che la nostra applicazione non sarà compilata a 64 bit ma bensì a 32 bit. Questo potrebbe comportare qualche problema nel futuro, se Microsoft deciderà prima o poi di chiudere il supporto ai 32 bit sui sistemi operativi a 64 bit.
Vediamo ora come si utilizza il provider JET 4.0 per Access: in particolare le stringhe di connessione ai database Access cambiano a seconda che utilizziamo Access 2003 o Access 2007:
' Access 2003: Dim stringaconn As String = _ "Provider=Microsoft.JET.OLEDB.4.0;Data Source=" & _ "c:\test\prova2.mdb" ' Access 2007: Dim stringaconn As String = _ "Provider=Microsoft.ACE.OLEDB.12.0;" & _ "Data Source=c:\test\prova2.accdb;" & _ "Persist Security Info=False;"
Per maggiori dettagli sulle stringhe di connessione di ciascun provider dati (anche non-Access), date un’occhiata al sito www.connectionstrings.com.
Scriviamo quindi il programma finale per inserire un record in una tabella Access (2003 o 2007):
- creiamo un nuovo progetto in Visual Basic 2008;
- nel form predefinito aggiungiamo due TextBox di nome txtCognome e txtNome, nonché un pulsante per eseguire il frammento di codice;
- inserire il seguente codice a livello di form (di nome Form1):
Imports System.Data.OleDb Public Class Form1 Private Sub cmdInserisci_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles cmdInserisci.Click ' Access 2003: 'Dim stringaconn As String = _ ' "Provider=Microsoft.JET.OLEDB.4.0;Data Source=" & _ ' "c:\test\prova2.mdb" ' Access 2007: Dim stringaconn As String = _ "Provider=Microsoft.ACE.OLEDB.12.0;" & _ "Data Source=c:\test\prova2.accdb;" & _ "Persist Security Info=False;" Dim objconn As New OleDbConnection(stringaconn) objconn.Open() Dim stringasql As String = _ "Insert into prova2(Cognome,Nome) " & _ "values(@cognome, @nome)" Dim objcomm As New OleDbCommand(stringasql, objconn) objconn = New OleDbConnection(stringaconn) objconn.Open() objcomm = New OleDbCommand(stringasql, objconn) objcomm.Parameters.Add(New OleDbParameter("@cognome", _ Me.txtCognome.Text)) objcomm.Parameters.Add(New OleDbParameter("@nome", _ Me.txtNome.Text)) Try Dim righeAggiornate As Integer = objcomm.ExecuteNonQuery If righeAggiornate = 1 Then MessageBox.Show("tutto bene") Catch ex As Exception MessageBox.Show(ex.Message & _ Environment.NewLine & ex.StackTrace, "Errore") Finally objconn.Close() Me.txtCognome.Text = "" Me.txtNome.Text = "" Me.txtCognome.Focus() End Try End Sub End Class
Naturalmente, per utilizzare alternativamente Access 2003 o Access 2007, è sufficiente commentare/decommentare la definizione della stringa di connessione opportuna.
[VS 2008] Tabella comparativa dei prodotti
Ogni tanto leggo che qualcuno chiede di conoscere quali sono le differenze tra le varie versioni di Visual Studio 2008, dalla Express alla Team System, e quindi eccomi pronto a soddisfare ogni curiosità!
E’ possibile scaricare da qui un file in formato Word (.docx), PDF o XPS, con tutte le differenze tra le varie versioni. Sono ben 35 pagine di tabelle! … Purtroppo tutte in inglese.
Ma non c’è problema: per chi non conosce bene l’inglese, c’è anche la pagina specifica in italiano. Unico problema che quando provate a stamparla, anche se espandete tutte le voci, vi apparirà la pagina con le voci compresse ;-P
Del resto è inutile lamentarsi: “per ben apparire, un po’ bisogna soffrire”! 😀
[VB.NET] Valutazione di espressioni grazie a System.Reflection
Mi è capitato più volte di leggere delle richieste di funzioni per la valutazione di espressioni matematiche, tipo questa:
3+2*((5*3)-(20/10))
Una buona soluzione è stata scritta da Corrado Cavalli in un post di “MSDN Tips & Tricks” e precisamente utilizzando le librerie System.Reflection e System.CodeDom. Il post, realizzato con codice VB.NET e C#, si trova qui.
#46: VB.NET – impedire lo spostamento di un form
Prendo l’occasione di una discussione intercorsa oggi nella lista/forum “dotnet” di VB T&T, tra me e Riccardo Girardi, il quale aveva la necessità di trovare il modo per bloccare la posizione di un form. La gestione dell’evento di spostamento del form stesso non andava bene, perché causava un brutto sfarfallìo (flickering).
Ho trovato nel blog di Luciano Bastianello il codice in C# con cui viene realizzata questa funzionalità e l’ho convertito in VB.NET, con una correzione da parte di Riccardo Girardi:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) Const WM_NCLBUTTONDOWN As Integer = 161 Const WM_SYSCOMMAND As Integer = 274 Const HTCAPTION As Integer = 2 Const SC_MOVE As Integer = 61456 If (m.Msg = WM_SYSCOMMAND) AndAlso _ (m.WParam.ToInt32() = SC_MOVE) Then Return End If If (m.Msg = WM_NCLBUTTONDOWN) AndAlso _ (m.WParam.ToInt32() = HTCAPTION) Then Return End If MyBase.WndProc(m) End Sub
E’ sufficiente inserire questo codice all’interno del codice del form da bloccare e il gioco è fatto.
#45: ADO.NET Leggere la chiave del record appena inserito in SQL Server
Uno dei problemi che più frequentemente mi vengono posti riguarda la possibilità di inserire un nuovo record in una tabella e di conoscere il valore assegnato dal DBMS al campo auto incrementante.
Questo problema è solitamente risolto, peraltro in modo brillante ed elegante, con una specifica stored procedure (SP) di SQL Server. Qualcuno, però, chiede come si può fare direttamente da codice, senza “scomodare” una stored procedure.
Ad un primo esame, non abbiamo la possibilità di inserire il record e subito dopo leggere il valore del campo IDENTITY, perché nel frattempo, tra la nostra scrittura del record e la nostra lettura della chiave, qualche altro utente potrebbe aver inserito un nuovo record.
Queste due operazioni, invece, devono essere fatte in un unico blocco, cioè devono essere eseguite in un’unica transazione (principio di “atomicità” della transazione).
A questo proposito c’è una particolarità di SQL Server che possiamo utilizzare per risolvere questo problema: in T-SQL possono essere eseguite più istruzioni in sequenza, senza soluzione di continuità, semplicemente separando ciascuna istruzione con un punto e virgola (;).
In questo modo le singole istruzioni saranno eseguite una dopo l’altra senza interrompere la transazione e restituendo, così, il corretto valore della colonna IDENTITY.
Un esempio di codice di questa tecnica è il seguente:
Dim cn As System.Data.SqlClient.SqlConnection Dim cnStr = "Data Source = HP\SQL2008EXPRESS;" & _ "Initial Catalog=NOMEDATABASE;" & _ "Password=PIPPO;" & _ "User ID=sa;" & _ "Persist Security Info=True" cn = New System.Data.SqlClient.SqlConnection(cnStr) cn.Open() Dim cmd As New System.Data.SqlClient.SqlCommand( _ "SET NOCOUNT ON; INSERT INTO Tabella (ANAnome) " & _ "VALUES ('De Ghetto Mario'); " & _ "SELECT SCOPE_IDENTITY() AS ANAID;", cn) Dim risultato = cmd.ExecuteScalar() MessageBox.Show("Il nuovo ID inserito è " & risultato) cn.Close() cn = Nothing
Attenzione a impostare correttamente i parametri della stringa di connessione (nome dell’istanza, nome del database, utente e password), altrimenti non potrete collegarvi correttamente alla fonte dati.
#43: Spostare un insieme di file in una diversa cartella con VB.NET (anche con LINQ)
Per spostare un file da una cartella a un’altra, possiamo utilizzare semplicemente il metodo My.Computer.FileSystem.MoveFile.
Il problema consiste nel fatto che questo metodo non consente di utilizzare i caratteri jolly e quindi non possiamo eseguire questa istruzione:
My.Computer.FileSystem.MoveFile( _
“C:\Test1\*.jpg”, “C:\Test2\*.jpg”)
Abbiamo quindi la necessità di recuperare prima di tutto i nomi di tutti i file che rispondono a un determinato schema come *.jpg, poi potremo spostare i file singolarmente, utilizzando un ciclo For Each:
Imports System.IO
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
‘ creazione array con elenco file *.jpg:
Dim d As New DirectoryInfo(“C:\Test1”)
Dim f As FileInfo() = d.GetFiles(“*.jpg”)
‘ ciclo di spostamento:
For Each fNext In f
My.Computer.FileSystem.MoveFile( _
“C:\Test1\” & fNext.Name, _
“C:\Test2\” & fNext.Name)
Next
End Sub
End Class
Da qui possiamo poi creare una procedura riutilizzabile più volte, inserendola in un modulo di codice:
Imports System.IO
Module Utility
Public Sub spostaGruppoFile(ByVal nomeFile As String, _
ByVal dir1 As String, ByVal dir2 As String)
‘ creazione array con elenco file *.jpg:
Dim d As New DirectoryInfo(dir1)
Dim f As FileInfo() = d.GetFiles(nomeFile)
‘ ciclo di spostamento:
For Each fNext In f
My.Computer.FileSystem.MoveFile( _
dir1 & fNext.Name, _
dir2 & fNext.Name)
Next
End Sub
End Module
Tale procedura può essere chiamata semplicemente come segue, passando il nome del file o lo schema (con i caratteri jolly), la cartella di origine e la cartella di destinazione:
spostaGruppoFile(“*.jpg”, “C:\Test1\”, “C:\Test2\”)
Imports System.IO
Module Utility
Public Sub spostaGruppoFile(ByVal nomeFile As String, _
ByVal dir1 As String, ByVal dir2 As String)
‘ creazione array con elenco file:
Dim d As New DirectoryInfo(dir1)
Dim f = From elenco In d.GetFiles(nomeFile) _
Select elenco.Name
‘ ciclo di spostamento:
For Each fNext In f
My.Computer.FileSystem.MoveFile( _
dir1 & fNext, _
dir2 & fNext)
Next
End Sub
End Module
#42: Abbreviare la dimensione di un file con VB.NET
Come tutti i programmatori sanno, in informatica vengono utilizzate delle abbreviazioni per indicare l’unità di misura per la dimensione di un file, della RAM o di un hard disk: per esempio un file di 1.024 byte equivale a un file di 1 “kB”.
Le abbreviazioni utilizzate attualmente sono le seguenti:
- kiloByte –> kB –> 1.024 (circa 10^3)
- MegaByte –> MB –> 1.048.576 (circa 10^6)
- GigaByte –> GB –> 1.073.741.824 (circa 10^9)
- TeraByte –> TB –> 1.099.511.627.776 (circa 10^12)
- PetaByte –> PB –> 1.125.899.906.842.620 (circa 10^15)
- ExaByte –> EB –> 1.152.921.504.606.850.000 ( circa 10^18 )
- ZettaByte –> ZB –> 1,180.591.620.717.41E+21 (circa 10^21)
- YottaByte –> YB –> 1,208.925.819.614.63E+24 (circa 10^24)
Per noi programmatori potrebbe quindi essere utile avere una funzione in grado di abbreviare un numero molto grande, così da avere una rappresentazione molto più compatta. Il seguente codice fa proprio questo:
Module Module1
Public Function ConvertiByte( _
ByVal strNumero As String) As String
Dim risultato As String
Dim potenza As Integer = 0
Dim nByte As Decimal = 0
‘ verifico se è stato passato un parametro:
‘ se si, lo converto nel tipo Decimal
‘ se no, esco
‘TODO: aggiungere verifica se è un numero valido!
If strNumero <> “” Then
Try
nByte = CType(strNumero, Decimal)
Catch ex As Exception
Return “Numero troppo grande: Overflow”
End Try
Else
Return “Errore: nessun numero da valutare”
End If
‘ ciclo di riduzione del numero, estraendo
‘ il numero di iterazioni effettuate
Do While ((nByte / 1000) >= 1)
nByte = nByte / 1024
potenza += 1
Loop
‘ conversione in stringa con arrotondamento
risultato = Decimal.Round(nByte, 2).ToString
‘ aggiunta della giusta unità di misura
Select Case potenza
Case 0
risultato &= ” byte”
Case 1
risultato &= ” KB”
Case 2
risultato &= ” MB”
Case 3
risultato &= ” GB”
Case 4
risultato &= ” TB”
Case 5
risultato &= ” PB”
Case 6
risultato &= ” EB”
Case 7
risultato &= ” ZB”
Case 8
risultato &= ” YB”
Case Else
risultato = “Non valutabile”
End Select
Return risultato
End Function
End Module
A questo punto basta creare un form, aggiungere una casella di testo e un pulsante. Il codice per gestire l’evento Click del pulsante è il seguente:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
MessageBox.Show(ConvertiByte(Me.TextBox1.Text))
End Sub
End Class
Semplice vero? Ma proviamo a migliorare un po’ la nostra funzione. E’ sufficiente sostituire tutto il codice seguente al commento “aggiunta della giusta unità di misura”:
‘ aggiunta della giusta unità di misura
Dim misure() As String = _
{“byte”, “KB”, “MB”, “GB”, “TB”, “PB”, “EB”, “ZB”, “YB”}
If potenza > 8 Then
risultato &= ” Non valutabile”
Else
risultato &= ” “ & misure(potenza)
End If
Return risultato
Con una semplice modifica, poi, possiamo fare in modo che la nostra funzione rappresenti un’abbreviazione di potenze di 10^3. Per esempio (i punti di separazione delle migliaia sono inseriti solo per chiarezza visiva):
– 1.000 –> 1 x 10^3
– 1.000.000 –> 1 x 10^6
– 55.555.555.555 –> 55,56 x 10^9
Ecco quindi la nostra funzione modificata:
Module Module1
Public Function ConvertiByte( _
ByVal strNumero As String) As String
Dim risultato As String
Dim potenza As Integer = 0
Dim nByte As Decimal = 0
‘ verifico se è stato passato un parametro:
‘ se si, lo converto nel tipo Decimal
‘ se no, esco
‘TODO: aggiungere verifica se è un numero valido!
If strNumero <> “” Then
Try
nByte = CType(strNumero, Decimal)
Catch ex As Exception
Return “Numero troppo grande: Overflow”
End Try
Else
Return “Errore: nessun numero da valutare”
End If
‘ ciclo di riduzione del numero, estraendo
‘ il numero di iterazioni effettuate
Do While ((nByte / 1000) >= 1)
nByte = nByte / 1000
potenza += 1
Loop
‘ conversione in stringa con arrotondamento
risultato = Decimal.Round(nByte, 2).ToString
‘ aggiunta della giusta unità di misura
risultato &= ” x 10^” & (potenza * 3).ToString
Return risultato
End Function
End Module
Come potete vedere, le uniche differenze sono date dal diverso divisore (1000 anziché 1024) e nella parte finale, dove viene composta la stringa che viene restituita dalla funzione al codice chiamante.
Una precisazione, prima che qualcuno possa pensare che si tratti di un errore. Il seguente codice:
Do While ((nByte / 1000) >= 1)
nByte = nByte / 1024
potenza += 1
Loop
potrebbe apparire strano o perfino sbagliato. Perché confronto la divisione per 1000 e poi divido per 1024?
E’ molto semplice: nel caso in cui, per esempio, volessi abbreviare 1000 byte, con il confronto per 1024 otterrei la non esecuzione dell’abbreviazione e quindi il risultato sarebbe “1000 byte” anziché “0,98 KB”. Di solito è abbastanza brutto veder superare il valore di 1000 in questi casi e quindi si preferisce comunque arrivare al massimo a 999 (confrontate per esempio con la visualizzazione dell’Esplora Risorse di Windows).
Una curiosità: notate come sia possibile, in VB.NET, scrivere una cosa del genere:
(potenza * 3).ToString
senza dover memorizzare il calcolo matematico in una variabile.
C’è ancora qualcuno che non è convinto a passare a VB.NET? 🙂
#41: Scaricare il contenuto HTML di una pagina web con VB.NET
Nel precedente post abbiamo visto come è possibile estrarre il testo semplice da una pagina HTML registrata sul disco fisso. In questo post, invece, vedremo come è possibile scaricare il contenuto HTML di una pagina web, fornendo semplicemente l’URL, e come da questa è possibile estrarre il testo semplice.
Procediamo per gradi: innanzi tutto creiamo una nostra classe (ScaricaURL) per gestire la comunicazione con il web server.
Imports System.Text
Imports System.IO
Imports System.Net
Public Class ScaricaURL
Private m_strURL As String
Public Sub SetURL(ByVal strURL As String)
m_strURL = strURL
End Sub
Public Function Scarica() As String
Dim wreq As WebRequest = WebRequest.Create(m_strURL)
Dim wres As WebResponse = wreq.GetResponse()
Dim iBuffer As Integer = 0
Dim buffer( 128 ) As [Byte]
Dim stream As Stream = wres.GetResponseStream()
iBuffer = stream.Read(buffer, 0, 128 )
Dim strRes As New StringBuilder(“”)
While iBuffer <> 0
strRes.Append(Encoding.ASCII.GetString(buffer, 0, iBuffer))
iBuffer = stream.Read(buffer, 0, 128 )
End While
Return strRes.ToString()
End Function
End Class
Successivamente inseriamo in un form: due pulsanti (Button1 e Button2) e un textbox (TextBox1). Quest’ultimo dovrà essere configurato come nel post precedente: proprietà Multiline a True e Scrollbar verticale.
Il codice dei gestori degli eventi Click dei due pulsanti sono i seguenti:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim URL As String
URL = “http://community.visual-basic.it/mario/” & _
“archive/2008/06/29/23164.aspx”
Dim objScaricaURL As New ScaricaURL
objScaricaURL.SetURL(URL)
Me.TextBox1.Text = objScaricaURL.Scarica
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
Dim URL As String
URL = “http://community.visual-basic.it/mario/” & _
“archive/2008/06/29/23164.aspx”
Dim objScaricaURL As New ScaricaURL
objScaricaURL.SetURL(URL)
Me.TextBox1.Text = _
System.Text.RegularExpressions.Regex.Replace( _
objScaricaURL.Scarica, “<[^>]*>”, “”)
End Sub
End Class
Vedrete quindi che premendo il primo pulsante il programma scaricherà la pagina e visualizzerà il relativo codice HTML, mentre nel secondo caso scaricherà la pagina ed estrarrà solamente il testo semplice, eliminando tutti i tag HTML.
#40: Estrarre il testo da una pagina HTML con VB.NET
Le espressioni regolari sono uno strumento estremamente potente per estrarre del testo da una pagina HTML registrata su disco.
Una delle cose più interessanti è il fatto che possiamo raggiungere questo obiettivo con una sola riga di codice!
Ecco qui la nostra funzione:
Public Function EstraiTestoDaHTML(ByVal HTML As String) As String
‘ rimuove i tag HTML
Return System.Text.RegularExpressions.Regex.Replace( _
HTML, “<[^>]*>”, “”)
End Function
… ed ecco il codice, inserito nel gestore dell’evento Click di un pulsante:
Dim testoHTML As String
testoHTML = My.Computer.FileSystem.ReadAllText(“C:\paginaX.html”)
Me.TextBox1.Text = EstraiTestoDaHTML(testoHTML)
A questo punto basta inserire una casella di testo di nome TextBox1, impostare la sua proprietà Multiline a True e definire la scrollbar verticale e il gioco è fatto!
#39: Aggiungere un collegamento ai Preferiti con VB.NET
Tempo addietro ho avuto la necessità di creare un piccolo programma per aggiungere un collegamento ai Preferiti, per permettere a un numero consistente di utenti dell’azienda dove lavoro di collegarsi a un nostro sito interno, nella Intranet aziendale.
Il programma è estremamente semplice, come si può vedere dal seguente codice:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
CreaShortcut(“Prova”, “http://www.visual-basic.it”)
End Sub
Public Sub CreaShortcut(ByVal Titolo As String, ByVal URL As String)
‘ crea uno shortcut nella cartella Preferiti
Dim strCartellaPreferiti As String
‘ recupera la cartella Preferiti
strCartellaPreferiti = System.Environment.GetFolderPath( _
Environment.SpecialFolder.Favorites)
‘ crea uno shortcut basato su Titolo
Dim objSW As System.IO.StreamWriter = _
System.IO.File.CreateText(strCartellaPreferiti & _
“\” & Titolo & “.url”)
‘ scrive l’URL nel file
objSW.WriteLine(“[InternetShortcut]”)
objSW.WriteLine(“URL=” & URL)
‘ chiude il file
objSW.Close()
End Sub
End Class
Nel form ho inserito un pulsante che semplicemente richiama la Sub CreaShortcut, passandogli il titolo del collegamento e l’indirizzo (URL) del collegamento vero e proprio.
Nella Sub CreaShortcut, invece, viene prima di tutto recuperato il percorso della cartella speciale dei Preferiti, poi viene aperto uno stream per la scrittura del file, all’interno del quale vengono inserite due righe di testo: la prima con un “tag” speciale che specifica che il file costituisce una “scorciatoia” a un indirizzo internet e la seconda con l’URL vero e proprio. Infine il file viene correttamente chiuso.
N.B.: questo mio post fa parte di alcuni suggerimenti di programmazione per i quali traggo ispirazione, spesso, da richieste che vedo nelle liste VB T&T oppure in giro per la Rete. Spero che vi possano interessare… 🙂
#38: spostare un file nel Cestino con VB.NET
Per permettere agli utenti dei vostri programmi di spostare un file nel Cestino di Windows (alias “Recycle Bin”) dobbiamo utilizzare una funzione della libreria di sistema shell32.dll.
Per rendere più semplici le cose, potete utilizzare il seguente modulo di codice:
Imports System.IO
Module SpostaFileCestino
Private Structure ShFileOpStruct
Dim hwnd As Integer
Dim wFunc As Integer
Dim pFrom As String
Dim pTo As String
Dim fFlags As Short
Dim fAnyOperationAborted As Boolean
Dim hNameMappings As Integer
Dim lpszProgressTitle As String
End Structure
Private Const SFC_DELETE As Short = &H3S
Private Const SFC_ALLOWUNDO As Short = &H40S
Private Const SFC_NOCONFIRMATION As Short = &H10S
Private Declare Function ShFileOperation _
Lib “shell32.dll” _
Alias “SHFileOperationA” _
(ByRef lpFileOp As ShFileOpStruct) As Integer
Public Function Ricicla(ByRef sPath As String) As Integer
Dim FileOp As ShFileOpStruct
If Not File.Exists(sPath) Then
MessageBox.Show(“File “ & sPath & ” non trovato.”)
Return -1
Exit Function
End If
With FileOp
.wFunc = SFC_DELETE
.pFrom = sPath & vbNullChar
.pTo = vbNullChar
.fFlags = SFC_NOCONFIRMATION Or SFC_ALLOWUNDO
.lpszProgressTitle = “Invio file “ & _
sPath & ” al Cestino di Windows.”
End With
Try
ShFileOperation(FileOp)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Return 0
End Function
End Module
Infine, per utilizzare effettivamente la funzione Ricicla potete fare riferimento al seguente esempio:
Dim esito As Integer = 0
esito = Ricicla(“C:\prova.txt”)
If esito = -1 Then
MessageBox.Show(“Errore: operazione annullata!”)
Else
MessageBox.Show(“Spostamento nel Cestino “ & _
“eseguito correttamente.”)
End If
L’utilizzo non richiede ulteriori commenti, dato che è sufficiente passare alla funzione Ricicla il nome del file completo del percorso.
#37: Trucco per commentare blocchi di codice con VB.NET
Come è noto a tutti i programmatori Visual Basic, con questo linguaggio non è possibile commentare blocchi di codice o di testo e ci si deve rassegnare a commentare riga per riga con l’apice singolo (‘). I programmatori C#, C++ e JAVA, invece, hanno una sintassi specifica estremamente comoda che si presenta così:
/*
Qui posso scrivere quello che voglio
senza nessun problema!!
*/
Con il seguente trucco, però, possiamo simulare la stessa situazione di cui sopra: è sufficiente utilizzare la direttiva #If … #End If.
Create una nuova applicazione Windows Forms (linguaggio Visual Basic) e aggiungete un pulsante nel form principale. Sostituite poi il codice sottostante con il seguente:
Public Class Form1
Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
MessageBox.Show(“Trucco per ” & _
“commentare blocchi di codice…”)
#If False Then
MessageBox.Show(“Questo non dovrebbe apparire…”)
Posso scrivere qualsiasi cosa!
#End If
MessageBox.Show(“Fine trucco!”)
End Sub
End Class
Eseguendo il programma, vedrete apparire il primo messaggio (“Trucco per…”) e poi l’ultimo messaggio (“Fine trucco!”), mentre tutto ciò che è stato inserito nel blocco #If … #End If è totalmente ignorato, sia che si tratti di un’istruzione valida, sia che si tratti di puro testo.
Certo, non è così ordinato e intuitivo come la coppia /* … */ di C#, ma è utile per commentare velocemente parti di codice che vogliamo temporaneamente disattivare o per inserire lunghi commenti descrittivi.
Come funziona? Il blocco #If … #End If è tecnicamente una direttiva per il compilatore: quest’ultimo, trovando #If, eseguirà il test indicato subito dopo. Se il test risulterà negativo (False), come nel caso sopra illustrato, ignorerà tutto ciò che troverà successivamente fino a #End If, se invece risulterà positivo (True), eseguirà il codice contenuto al suo interno.
Uno degli usi più importanti di questa direttiva è, oltre tutto, eseguire del codice condizionale a seconda che ci si trovi in modalità di DEBUG o in modalità RELEASE.
#36: Calcolare il tempo di esecuzione di un frammento di codice (VB.NET)
Sviluppando o studiando una nuova tecnica, in un qualsiasi linguaggio di programmazione, spesso abbiamo bisogno di avere una valutazione oggettiva del tempo di esecuzione di più frammenti di codice, per poter valutare quale dei due impiega meno tempo. Infatti il minore tempo di esecuzione di certe parti di codice, specialmente quelle ripetute più volte nel corso del programma o utilizzate in più parti del programma stesso, ha per conseguenza un minore tempo di esecuzione dell’intero programma e quindi migliori prestazioni che vengono percepite positivamente dall’utente.
In questo post vedremo quindi come si crea e come si utilizza una classe in grado di memorizzare il momento iniziale di un test e la differenza tra un momento successivo e il momento iniziale.
La classe è la seguente:
Public Class Cronometro
Private inizio As DateTime
Private durata As TimeSpan
Public Sub New()
inizio = New DateTime
durata = New TimeSpan
End Sub
Public Sub ferma()
durata = CType(DateTime.Now.Subtract(inizio), TimeSpan)
End Sub
Public Sub avvia()
GC.Collect()
GC.WaitForPendingFinalizers()
inizio = DateTime.Now
End Sub
Public ReadOnly Property Result() As TimeSpan
Get
Return durata
End Get
End Property
End Class
Le istruzioni GC.Collect() e GC.WaitForPendingFinalizers() servono per avviare la “raccolta della spazzatura” da parte del Garbage Collector, cioè l’eliminazione degli oggetti non più utilizzati. Infatti, come sappiamo, gli oggetti non vengono eliminati immediatamente al termine del loro utilizzo, ma rimangono in memoria finché il Garbage Collector non decide di eliminarli. In particolare la seconda istruzione (GC.WaitForPendingFinalizers) attende che siano terminati tutti i metodi Finalizer degli oggetti in corso di eliminazione.
Perché avviare esplicitamente il Garbage Collector? E’ presto detto: vogliamo che nel corso del nostro test non avvenga la “raccolta dei rifiuti” che rallenterebbe l’esecuzione e causerebbe l’invalidazione del test stesso.
In un’applicazione Console possiamo poi testare la classe Cronometro con questo codice:
Option Strict On
Imports System.Console
Module Module1
Sub Main()
Dim numeri(99999) As Integer
BuildArray(numeri)
Dim tObj As New Cronometro()
tObj.avvia()
ScriviNumeri(numeri)
tObj.ferma()
Console.WriteLine(“tempo in secondi: “ & _
tObj.Result.TotalSeconds)
Console.Read()
End Sub
Sub BuildArray(ByVal arr() As Integer)
Dim indice As Integer
For indice = 0 To 99999
arr(indice) = indice
Next
End Sub
Sub ScriviNumeri(ByVal arr() As Integer)
Dim indice As Integer
For indice = 0 To arr.GetUpperBound(0)
Console.Write(arr(indice) & ” “)
Next
End Sub
End Module
Quella che abbiamo visto è la soluzione “classica” che viene spesso utilizzata e che, peraltro, va bene con qualsiasi linguaggio OOP (anche quelli non-.NET, fatti gli opportuni adattamenti).
E’ possibile ottenere una soluzione più ordinata e pulita utilizzando la classe System.Diagnostics.Stopwatch, implementata in tutti i Framework .NET dalla versione 2.0 in poi. Per esempio questo è il codice di un’applicazione Console che fa uso di tale classe:
Public Class Test
Shared Sub main()
Dim str As String = “”
Dim watch As New System.Diagnostics.Stopwatch()
watch.Start() ‘ avvio del cronometro
‘ … fai qualcosa …
Dim i As Integer = 0
For i = 1 To 100
str &= “*”
Console.WriteLine(“<“ & str & “>”)
Next
watch.Stop() ‘ stop del cronometro
Console.WriteLine(“Tempo impiegato: “ + watch.Elapsed.ToString())
Console.ReadLine()
End Sub
End Class
Attenzione che il test può non funzionare perfettamente in tutti i casi: se il nostro computer è pieno di programmi e servizi in esecuzione, potremmo ottenere dei risultati non corretti. In particolare, quando dobbiamo confrontare i tempi di due versioni di codice diverse (per esempio due algoritmi di ordinamento diversi), lo stato del computer dovrebbe essere il più possibile uguale in entrambe le esecuzioni, altrimenti si rischia di falsare i risultati.
Il consiglio è sempre quello, se possibile, di utilizzare un’installazione “pulita”, con solo i programmi e i servizi indispensabili per l’esecuzione del programma e del relativo test.
#35: Cancellare la lista dei progetti
Sono molti i programmatori che sentono la mancanza di un metodo per cancellare la lista (o una parte della lista) dei progetti nell’ambiente di sviluppo.
L’unico modo per farlo è quello di intervenire a livello di registro di sistema, eliminando le chiavi contenute nelle seguenti voci di registro:
Visual Studio 2008 Professional:
HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\ProjectMRUList
Visual Basic 2008 Express:
HKEY_CURRENT_USER\Software\Microsoft\VBExpress\9.0\ProjectMRUList
Visual Web Developer 2008 Express:
HKEY_CURRENT_USER\Software\Microsoft\VWDExpress\9.0\ProjectMRUList
Visual C# 2008 Express:
HKEY_CURRENT_USER\Software\Microsoft\VCSExpress\9.0\FileMRUList
NOTA – attenzione alle modifiche che apportate al registro di sistema: basta molto poco per danneggiare l’installazione di Windows!
*** AGGIORNAMENTO ***
Su questo argomento si sono “sbizzarriti” anche, dapprima, Alessandro Del Sole che ha pubblicato nel suo blog l’annuncio di un add-in creato da lui stesso e pubblicato su Code Gallery di MSDN, poi Diego Cattaruzza che ha pubblicato nel suo blog l’annuncio di un “non-add-in” per le versioni Express.
In conclusione, ora avete anche degli strumenti più “user-friendly” per eliminare la lista dei progetti anche senza rischiare di maneggiare maldestramente il registro di sistema!
#34: Problema di duplicazione menu con IDE di VS 2008 Pro
A ogni avvio, VS 2008 Professional (Trial) aveva iniziato a segnalare l’impossibilità di caricare alcuni pacchetti (add-in o altri) e per ognuno consigliava di digitare “devenv /ResetSkipPkgs” da riga di comando per risolvere il problema.
Oggi ho eseguito tale comando e il risultato è che… i menu si sono duplicati al loro interno e quadruplicati nel loro insieme! In pratica questo è il menu principale risultante:
File File Modifica Modifica Visualizza Visualizza Strumenti Strumenti Test Test Finestra Finestra ? ? File File Modifica Modifica Visualizza Visualizza Strumenti Strumenti Test Test Finestra Finestra ? ? File File Modifica Modifica Visualizza Visualizza Strumenti Strumenti Test Test Finestra Finestra ? ? File File Modifica Modifica Visualizza Visualizza Strumenti Strumenti Test Test Finestra Finestra ? ?
E’ vero che le voci sono ugualmente accessibili, ma è anche vero che è abbastanza fastidioso, oltre al fatto che occupa spazio prezioso.
Ho provato a reinstallare con il CD di setup utilizzando l’opzione “ripara” e fortunatamente ha funzionato.
Mi piacerebbe proprio sapere il motivo per cui quel comando ha dato un esito così infausto…
#33: Creare un GUID con Visual Studio 2008
Questa tip è un po’ diversa dal solito perché non presenta codice, ma mostra una funzionalità dell’IDE di Visual Studio 2008 Professional.
Infatti l’IDE di Visual Studio 2008 Professional offre la possibilità di creare automaticamente un GUID, cioè un Globally Unique Identifier, adatto anche all’uso nel registro di sistema. Alcuni esempi di GUID sono i seguenti:
{8ED66C10-25DC-4d49-9A7B-17E400202B81} {B359036E-53BD-492f-AE3C-28D8771759A0} {D310A47C-E9CD-48db-86B0-88439C7E5344}
La funzione per creare il GUID la trovate nel menu Strumenti > Crea GUID: scegliendo il formato “Registry format” otterrete proprio una stringa simile a quelle mostrate qui sopra. Se poi ne volete creare più di una, è sufficiente premere più volte il pulsante “New GUID” e naturalmente copiare ciascun GUID con il pulsante “Copy” (la copia avviene negli appunti di Windows, quindi bisogna poi “riversare” il codice GUID con CTRL+V da qualche altra parte).
#32: Elencare hard disk con spazio libero disponibile
In realtà la tip che presento oggi elenca gli hard disk ma anche gli eventuali dischi di altro tipo che dovessero essere disponibili nel sistema. Dato che alcune unità possono essere al momento prive di disco (es. l’unità per floppy disk A:, unità con disco removibile, lettori CD/DVD ecc.), è necessario gestire l’eccezione che interromperebbe l’esecuzione del programma.
Per provare questa tip è sufficiente creare un form, aggiungere un pulsante e una TextBox, impostare quest’ultima a “MultiLine” e inserire il seguente codice:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim driveInfo As System.IO.DriveInfo() = _
System.IO.DriveInfo.GetDrives()
For Each d As System.IO.DriveInfo In driveInfo
Try
TextBox1.Text += “Drive: “ + d.Name.ToString _
+ System.Environment.NewLine + “Size: “ _
+ d.TotalSize.ToString + System.Environment.NewLine _
+ System.Environment.NewLine + System.Environment.NewLine
Catch ex As Exception
‘ ignora gli errori dovuti a dischi “non hard disk”
‘ es. A:\ oppure lettori CD/DVD e unità non pronte
‘ (senza disco)
End Try
Next
End Sub
End Class
Ecco un esempio del risultato che possiamo ottenere:
#31: Aprire file XLS e creare un file CSV
Talvolta è necessario esportare i dati di un foglio Excel in un file di tipo testo con Campi Separati da Virgola (CSV) o, meglio, da punto e virgola.
Per ottenere questo risultato possiamo creare un nuovo progetto, inserire tra i riferimenti nelle proprietà del progetto la libreria Microsoft.Office.Interop.Excel, aggiungere un pulsante al form e, all’interno del suo evento Click, il codice seguente:
Imports Microsoft.Office.Interop.Excel
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim appExcel As Application = New Application
Dim cartella As Workbook = _
CType(appExcel.Workbooks.Open(“C:\ExcelVsCSV\Dati.xls”), Workbook)
cartella.SaveAs(“C:\ExcelVsCSV\Dati.csv”, XlFileFormat.xlCSV, _
CreateBackup:=False)
With appExcel
.DisplayAlerts = False
.Quit()
End With
End Sub
End Class
Provando l’esempio dopo aver creato il foglio Excel di nome Dati.xls (con qualsiasi dato in forma tabellare, comprese le intestazioni dei campi) nella cartella C:\ExcelVsCSV\, vedrete che verrà creato un file Dati.csv nella stessa cartella, con i dati separati da punto e virgola.
#30: Conteggio record con ADO.NET
L’articolo http://support.microsoft.com/kb/308050/en-us spiega che non è possibile conoscere in anticipo il numero di record restituiti dalla query con un DataReader, perché per conoscere il numero di
record è necessario spostarsi all’ultimo record. In quest’altro articolo viene sostanzialmente spiegata la stessa cosa: http://www.velocityreviews.com/forums/t112093-datareader-and-recordcount.html.
Per risolvere questo problema è possibile eseguire un conteggio PRIMA di aprire il DataReader, con istruzioni simili alle seguenti:
VB:
Dim cmd As SqlCommand = _
New SqlCommand("SELECT COUNT(*) FROM Clienti;", conn)
Dim numeroClienti As Integer = CInt(cmd.ExecuteScalar())
C#:
SqlCommand cmd = _ new SqlCommand("SELECT Count(*) FROM Clienti", conn); Int32 count = (Int32)cmd.ExecuteScalar;
#29: Svuotare tutte le TextBox di un form
Per svuotare tutte le TextBox di un form, è possibile utilizzare questo codice:
Dim ctrl As New Form.ControlCollection(Me)
ctrl = System.Windows.Forms.Form.ActiveForm.Controls
For Each c As Control In ctrl
If TypeOf (c) Is System.Windows.Forms.TextBox Then
c.Text = ""
End If
Next
#28: Progetti “usa e getta” in Visual Studio 2008
Specialmente quando studiamo una nuova tecnologia o una nuova tecnica di programmazione, in Visual Basic o in C#, può esserci utile evitare di salvare il progetto.
Infatti quello che vorremmo fare, dato che siamo persone ordinate (!), è semplicemente aprire un nuovo progetto senza salvarlo alla creazione, provare il codice e poi chiudere il progetto eliminando ogni sua traccia. In questo modo possiamo evitare di avere l’hard disk pieno di progetti di prova che provocano solo una grande confusione.
Possiamo realizzare tutto questo semplicemente modificando un’opzione di Visual Studio 2008, di Visual Basic 2008 Express o di Visual C# 2008 Express:
-
selezionate il menu Strumenti > Opzioni > Progetti e soluzioni > Generale (nella versione inglese: Tools > Options > Projects and Solutions > General);
-
nella scheda che apparirà, esiste una casella di controllo con la voce “Salva nuovi progetti alla creazione” (in inglese “Save new projects when created”): togliendo la spunta potremo disattivare la richiesta di salvataggio del progetto al momento della creazione!
#27: Conversione di una data da formato stringa a DateTime
Per convertire una stringa in formato “gg/mm/aaaa” in un oggetto di tipo DateTime, è possibile utilizzare la seguente funzione:
Private Function ToDateTime(ByVal _ dataGG_MM_AAAA As String) As DateTime Dim myCultureInfo As New _ System.Globalization.CultureInfo("it-IT", _ True) Dim formato As String = "dd/MM/yyyy" Return _ System.DateTime.ParseExact(dataGG_MM_AAAA, _ formato, myCultureInfo) End Function
Per testare questa funzione, invece, potete provare il seguente codice:
Private Sub Form1_Load(ByVal sender _ As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load Dim dataStringa As String Dim data As Date dataStringa = "01/03/2008" data = ToDateTime(dataStringa) MessageBox.Show(Month(data)) ' <-- visualizza "3" End Sub
#26: VB 2008 e LINQ to Objects
LINQ to Objects permette di eseguire interrogazioni su oggetti presenti in memoria.
Questa tecnica può essere applicata anche a un array, come possiamo vedere dal seguente esempio:
Public Class Form1 Private Sub Button1_Click(ByVal sender _ As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click ' variabili per composizione ' del messaggio finale: Dim messaggio As String = "" Dim NL As String = Environment.NewLine ' dichiarazione array: Dim frutti() As String = _ {"mela", "pera", "banana", "mandarino"} ' dichiarazione della variabile che conterrà ' l'insieme delle stringhe restituite dalla ' query. La query è dichiarata nella stessa ' istruzione: Dim fruttiPreferiti = _ From f In frutti _ Where f.StartsWith("m") _ Select f ' scorrimento dell'insieme delle stringhe ' per la composizione del messaggio: For Each frutto In fruttiPreferiti messaggio &= "Frutto: " & frutto & NL Next MessageBox.Show(messaggio) End Sub End Class
Le stringhe restituite dalla query sono “mela” e “mandarino”.
#25: Conversione di data e ora in stringa
Per convertire un dato di tipo DateTime in stringa formattata, possiamo utilizzare una delle forme del metodo ToString. Il seguente esempio mostra come è possibile ricavare la data e ora corrente, solo la data corrente e solo l’ora corrente:
Dim dt As DateTime
dt = DateTime.Now
‘ data e ora:
Dim dataOra As String = dt.ToString
‘ solo data in formato GG/MM/AAAA:
Dim data As String = dt.ToString(“dd/MM/yyyy”)
‘ solo ora in formato HH.MM.SS (ore da 0 a 23):
Dim ora As String = dt.ToString(“T”)
‘ stampa i tre valori:
Dim s As String = dataOra & Environment.NewLine & _
data & Environment.NewLine & ora
MessageBox.Show(s)
Il risultato sarà simile al seguente:
27/02/2008 20.36.23
27/02/2008
20.36.23