Array

lunedì 06 ottobre 2008 - 19.38

netgit Profilo | Newbie

Ciao a tutti.
Sono nuova a VB.net e forse ciò che cerco di fare non si può.
Esempio :
Ho definito questa classe :
Public Class Col_prop
Public Property colVisible() As Boolean
Get
Return p_colVisible
End Get
Set(ByVal value As Boolean)
p_colVisible = value
End Set
End Property
Public Property colWidth() As Integer
Get
Return p_colWidth
End Get
Set(ByVal value As Integer)
p_colWidth = value
End Set
End Property
Public Property colFormat() As Integer
Get
Return p_colFormat
End Get
Set(ByVal value As Integer)
p_colFormat = value
End Set
End Property
Public Property colAlignement() As Integer
Get
Return p_colAlignement
End Get
Set(ByVal value As Integer)
p_colAlignement = value
End Set
End Property
Public Property colSort() As Integer
Get
Return p_colSort
End Get
Set(ByVal value As Integer)
p_colSort = value
End Set
End Property
Dim p_colVisible As New Boolean
Dim p_colWidth As New Integer
Dim p_colFormat As New Integer
Dim p_colAlignement As New Integer
Dim p_colSort As New Integer
Public Sub New()
End Sub
End Class

Poi all'interno di un'altra classe :
Public Class PrintDGV
Dim p_dgv_prop(10) As Col_prop
Public Property DGV_property(ByVal row As Integer) As Col_prop
Get
Return p_dgv_prop(row)
End Get
Set(ByVal value As Col_prop)
p_dgv_prop(row) = value
End Set
End Property
.
.
.
.
Nel MAIN istanzio la PrintDGV
Dim Situ_dgv As New PrintDGV
e tutto va, ma poi quando cerco di settare le :
Situ_dgv.DGV_property(0).colVisible = True
segue l'errore :
Riferimento a un oggetto non impostato su un'istanza di oggetto.

Spero qualcuno sappia dirmi come fare.

Ciao

aiedail92 Profilo | Expert

Ciao

Non è che non si può fare, semplicemente i valori dell'array sono inizializzati a Nothing, quindi non puoi impostare variabili o chiamare funzioni membro (ecco perchè la NullReferenceException)

Per risolvere potresti ad esempio mettere nel costruttore l'inizializzazione per ogni elemento:

Public Class PrintDGV Dim p_dgv_prop(10) As Col_prop Public Property DGV_property(ByVal row As Integer) As Col_prop Get Return p_dgv_prop(row) End Get Set(ByVal value As Col_prop) p_dgv_prop(row) = value End Set End Property Public Sub New() 'Inizializza ogni elemento dell'array For i As Integer = 0 To p_dgv_prop.Length - 1 p_dgv_prop(i) = New Col_prop() Next End Sub End Class

Luca

netgit Profilo | Newbie

Provo e poi ti dico.
Mi sapresti dire come serializzare, penso sia il termine giusto, p_dgv_prop in un file xml ( esmpi o traccie per iniziare ) ?
Grazie mille dell'aiuto

netgit Profilo | Newbie

La tua soluzione è perfetta e mi chiarisce anche alcune cose.
Ho dovuto aggiungere :
InitializeComponent()
prima del for


ok !
Grazie ancora.
Ora vado a caccia di come serializzare in xml .

ciao

aiedail92 Profilo | Expert

Ciao

Per serializzare l'oggetto, non devi fare altro che assegnare alla classe l'attributo Serializable, quindi usare un XmlSerializer (per la serializzazione xml) o un BinaryFormatter per eseguire la serializzazione.

Eccoti l'esempio:

<Serializable()> _ Public Class PrintDGV Dim p_dgv_prop(10) As Col_prop Public Property DGV_property(ByVal row As Integer) As Col_prop Get Return p_dgv_prop(row) End Get Set(ByVal value As Col_prop) p_dgv_prop(row) = value End Set End Property Public Sub New() 'Inizializza ogni elemento dell'array For i As Integer = 0 To p_dgv_prop.Length - 1 p_dgv_prop(i) = New Col_prop() Next End Sub End Class

Con questi due metodi serializzi e deserializzi (sono metodi generici, così puoi riutilizzarli per ogni tipo)

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

E questo è un modo in cui potresti usarlo:

'Crea l'oggetto da serializzare Dim obj As New PrintDGV() 'Serializza l'oggetto in binario '(per serializzare in xml passa True) Serialize(obj, "C:\out.dat", False) 'Deserializza l'oggetto da binario Dim newObj As PrintDGV = DeSerialize(Of PrintDGV)("C:\out.dat", False)

Luca

aiedail92 Profilo | Expert

Ho scordato di dirti:

L'XmlSerializer serializza solo le proprietà e i campi pubblici, mentre il BinaryFormatter serializza tutto, quindi nel tuo caso, dato che hai il campo privato e non esponi una proprietà non indicizzata per accedervi, per serializzare anche quel campo dovresti usare il BinaryFormatter (usando le funzioni che ti ho scritto, dovresti passare False come ultimo argomento)

Luca

netgit Profilo | Newbie

Ciò che cerco di fare è : scaricare in un file xml, al verificarsi dell'evento closing della form, i valori della classe col_prop, che sono memorizzati nel vettore p_dgv_prop.

netgit Profilo | Newbie

Ho fatto questa prova:
<XmlRoot("Class_colprop")> _ Public Class Col_prop Public Property colVisible() As Boolean Get Return p_colVisible End Get Set(ByVal value As Boolean) p_colVisible = value End Set End Property <XmlElement("Property_colwidth")> _ Public Property colWidth() As Integer Get Return p_colWidth End Get Set(ByVal value As Integer) p_colWidth = value End Set End Property <XmlElement("Property_colformat")> _ Public Property colFormat() As Integer Get Return p_colFormat End Get Set(ByVal value As Integer) p_colFormat = value End Set End Property <XmlElement("Property_colalignement")> _ Public Property colAlignement() As Integer Get Return p_colAlignement End Get Set(ByVal value As Integer) p_colAlignement = value End Set End Property <XmlElement("Property_colsort")> _ Public Property colSort() As Integer Get Return p_colSort End Get Set(ByVal value As Integer) p_colSort = value End Set End Property Dim p_colVisible As New Boolean Dim p_colWidth As New Integer Dim p_colFormat As New Integer Dim p_colAlignement As New Integer Dim p_colSort As New Integer Public Sub New() End Sub End Class

Nell evento closing :
Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra


Sbaglio qualcosa perchè quando deserializzo per impostare le proprietà salvate in xml ottengo :
Errore nel documento XML (8, 19).

Dim Situ_dgv As New PrintDGV Dim ob As New Col_prop Dim objStrRdr As StreamReader objStrRdr = New StreamReader("c:\abc.xml") Dim objXmlSer As New XmlSerializer(GetType(Col_prop)) i = 0 For i = 0 To 7 objLucky = DirectCast(objXmlSer.Deserialize(objStrRdr), Col_prop) Situ_dgv.DGV_property(i).colVisible = obj.colVisible Situ_dgv.DGV_property(i).colWidth = obj.colWidth Situ_dgv.DGV_property(i).colFormat = obj.colFormat Situ_dgv.DGV_property(i).colAlignement = obj.colAlignement Situ_dgv.DGV_property(i).colSort = obj.colSort i += 1 Next

Allego il file xml zippato , che creo in closing


ciao

aiedail92 Profilo | Expert

Il problema è che non puoi serializzare più elementi sullo stesso file: viene un formato xml non valido.

Prova ad esempio a sostutuire così il codice:

Private Sub Frmmain_Closing(ByVal sender As Object, ByVal e As CancelEventArgs) _ Handles MyBase.Closing 'Il serializer Dim objXmlSer As New XmlSerializer(GetType(Col_prop())) 'l'oggetto da serializzare Dim obj As New Col_prop 'Lo streamWriter Dim objStrWrt As StreamWriter objStrWrt = New StreamWriter("c:\abc.xml") 'La lista di oggetti da serializzare Dim objects As New List(Of Col_prop)() 'Popola la lista For Each col As DataGridViewColumn In dgv.Columns obj.colVisible = col.Visible obj.colWidth = col.Width obj.colFormat = col.DefaultCellStyle.Format obj.colAlignement = col.DefaultCellStyle.Alignment obj.colSort = col.SortMode objects.Add(obj) Next 'Serializza l'array objXmlSer.Serialize(objStrWrt, objects.ToArray()) 'Chiude lo stream objStrWrt.Close() End Sub Sub Deserialize() 'Il deserializzatore (deserializza un array) Dim deserializer As New XmlSerializer(GetType(Col_prop())) 'lo stream da deserializzare Dim stream As New StreamReader("C:\abc.xml") 'L'array deserializzato Dim objArray As Col_prop() = deserializer.Deserialize(stream) 'Imposta i valori dall'array For i As Integer = 0 To objArray.Length - 1 '... Next End Sub

Luca

netgit Profilo | Newbie

C'è qualcosa che non va, perchè in creazione scrive sempre lo stesso obj.
L'ho provato anche passo passo e i valori assegnati ad OBJ finiscono in tutti gli ITEMS di OBJECTS !!!
No dovrebbe comportarsi che con il metodo add aggiunge l'OBJ appena assegnato ed al ciclo successivo del for un altro con i nuovi valori ?

aiedail92 Profilo | Expert

Sì, errore mio, non avevo fatto caso che Col_prop è una classe e non una struttura.

Quindi devi reinizializzare l'oggetto ad ogni ciclo:

Private Sub Frmmain_Closing(ByVal sender As Object, ByVal e As CancelEventArgs) _ Handles MyBase.Closing 'Il serializer Dim objXmlSer As New XmlSerializer(GetType(Col_prop())) 'l'oggetto da serializzare Dim obj As Col_prop = Nothing 'Lo streamWriter Dim objStrWrt As StreamWriter objStrWrt = New StreamWriter("c:\abc.xml") 'La lista di oggetti da serializzare Dim objects As New List(Of Col_prop)() 'Popola la lista For Each col As DataGridViewColumn In dgv.Columns obj = New Col_prop() obj.colVisible = col.Visible obj.colWidth = col.Width obj.colFormat = col.DefaultCellStyle.Format obj.colAlignement = col.DefaultCellStyle.Alignment obj.colSort = col.SortMode objects.Add(obj) Next 'Serializza l'array objXmlSer.Serialize(objStrWrt, objects.ToArray()) 'Chiude lo stream objStrWrt.Close() End Sub

Luca

netgit Profilo | Newbie

scusa ma che differenza c'è fra una classe ed una struttura ?

aiedail92 Profilo | Expert

La differenza è che una struttura è un tipo valore, mentre una classe è un tipo di riferimento; il valore della classe quindi non è l'oggetto in sè, ma un riferimento ad un oggetto in memoria.

Quindi quando passi una struttura ad una funzione (ad esempio List.Add) quello che la funzione riceve è una copia dell'istanza, mentre se passi una classe, quello che la funzione riceve è una copia del riferimento all'istanza, quindi l'oggetto puntato è sempre lo stesso.

Questo significa che se fai List.Add con una struttura, aggiungi alla lista una copia della struttura, mentre se fai List.Add con una classe aggiungi un nuovo riferimento alla stessa classe, e se ne modifichi una risultano modificate tutte.

Spero di essere stato abbastanza chiaro...

Luca

netgit Profilo | Newbie

Allora col_prop sarebbe più corretto se venisse definito come struttura ?

aiedail92 Profilo | Expert

Non è "più giusto" o "più sbagliato", dipende da come devi usarli. Generalmente le strutture vengono usate quando le istanze hanno piccole dimensioni, e quando non devono essere estese (non si può ereditare da una struttura)

Guarda qui per le differenze fra classi e strutture: http://msdn.microsoft.com/it-it/library/2hkbth2a.aspx

Se decidi di mantenere una classe devi usare il secondo codice, se invece passi ad una struttura ti consiglio di tenere il primo per ragioni di performance.

Luca
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2023
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5