VORREI ANZITOTTO SEGNALARE AI MIEI VISITATORI CHE QUESTO BLOG CONTIENE ANCHE ARTICOLI! I post sono in primo piano, così ho scoperto che molti non accedono agli articoli. Per farlo, recarsi nella parte bassa della striscia di sinistra. Due recenti articoli di cui sono orgoglioso sono l'uno relativo a un ORIGINALE SISTEMA DI CRITTOGRAFIA DI UN FOGLIO EXCEL, l'altro dedicato al TRASFERIMENTO DI UNA TABELLA WORD IN EXCEL MEDIANTE LINQ. I link sono i seguenti (digitarli manualmente se occorre...):
http://blog.shareoffice.it/giannigiaccaglini/articles/9983.aspx
http://blog.shareoffice.it/giannigiaccaglini/articles/10068.aspx
Varianti inattese nei VSTO per Excel rispetto alle macro VBA
Riciclare macro VBA nei più “nobili” VSTO (Visual Studio Tools per Office) non è sempre indolore. La sintassi è più rigorosa e complessa, tra l’altro perché i VSTO fanno parte integrante dell’intero mondo Visual Studio. Nel caso di Excel, per dirne una, il basilare oggetto Range non viene immediatamente riconosciuto: come minimo il suo tipo va definito come Excel.Range, inoltre quando è usato come funzione la guida sembrerebbe che pretenda, per fare un classico esempio, un Global.Foglio1.Range(“A1:C10”). Poi si scopre che il solito Range(“A1:C10”) con foglio corrente sottinteso è accettato. Meno male, poi però si scoprono discrepanze non sempre prevedibili.
Andiamo in medias res con lo snippet seguente, in VSTO, ove con l’evidenziatore abbiamo indicato varianti significative rispetto al mondo VBA. Come tutti comprendono, la Sub associata al clic su un pulsante Button1 (si chiama CommandButton1 in VBA, poco male) genere una matrice Matr di un numero casuale di righe Nr e colonne Nc, riempita di vari Num, che poi viene copiata in un intervallo di pari dimensioni.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Nr As Integer = Int(Rnd()*10), Nc = Int(Rnd()*5)
Dim i As Integer = 0, j = 0, Num = 0
Dim Matr(0, 0) As Integer
ReDim Matr(Nr, Nc)
For i = 0 To Nr
For j = 0 To Nc
Matr(i, j) = Num
Num = Num + 1
Next
Next
Dim MiaZona As Excel.Range
'Copia Matr nell'intervallo "attorno" a cella attiva
With Application.ActiveCell
.CurrentRegion.ClearContents()
MiaZona = Range(.Cells(1, 1), .Cells(Nr, Nc))
End With
' MiaZona = Matr 'NON va!
For i = 0 To Nr
For j = 0 To Nc
MiaZona(i + 1, j + 1) = Matr(i, j)
Next
Next
End Sub
Prima variante. I VSTO non tollerano l’istruzione Redim da sola come in VBA, occorre farla precedere da Una Dim Matr(0, 0). Pazienza.
Seconda variante. Non è ammessa ActiveCell da sola, occorre Application.ActiveCell. Pazienza.
Terza variante. L’istruzione MiaZona = Matr è rifiutata! L’errore indicato è INVALID CAST EXCEPTION, una motivazione formale ineccepibile. Pazienza? Un po’ meno perché si perde una funzionalità potente e sintetica. In VBA si può infatti scrivere, semplicemente:
With ActiveCell
.CurrentRegion.ClearContents()
Range(.Cells(1, 1), .Cells(Nr, Nc)) = Matr
End With
Senza, tra l’altro, dover definire una specifica MiaZona e, soprattutto, senza il successivo loop per copiare gli elementi della Matr nelle celle del foglio.
Semplificazione dell’ultim’ora
Ripensandoci, ho poi scoperto che non è necessario definire un intervallo ad hoc MiaZona, di dimensioni adeguate a quelle della matrice, bensì ricorrere ad Application.ActiveCell – più lunga ma equivalente alla ActiveCell del mondo VBA - come qui sotto indicato:
With Application.ActiveCell
.CurrentRegion.ClearContents()
For i = 0 To Nr
For j = 0 To Nc
.Cells(i + 1, j + 1) = Matr(i, j)
Next
Next
End With
Il punto chiave è che con la proprietà indicizzata Cells(indRiga, indColonna) si accede a tutte le celle che circondano una data cella (la cella attiva nella fattispecie). Mai dimenticarsene!
?>
?>
?>