I'm here again trying to solve this issue with the ArrayList
that I've explained in this other question... the difference is that this time I'm not searching for any alternative solution such as the usage of other external file to avoid the real problem, I would really like to fix this using My.Settings and the ArrayList, I would like to understand what is happening here about My.Settings!.
The problem is that if we set a Setting like this:
Then any changes performed on the setting are preserved on the next app runs, this code demostrates the problem:
Public Class Test
Private Sub Test_Handler() Handles MyBase.Shown
' Create a temporal predefined ArrayList.
Dim tmpArrayList As New ArrayList(capacity:=10I)
With tmpArrayList
.Add({"Item0", 0.0F})
.Add({"Item1", 0.5F})
End With
' Check the setting status.
If My.Settings.MRU Is Nothing Then
Debug.WriteLine("MRU setting is null.")
Debug.WriteLine("Initializing the Setting...")
My.Settings.MRU = New ArrayList(capacity:=10I)
ElseIf My.Settings.MRU.Count = 0 Then
Debug.WriteLine("MRU is not null but the ArrayList is empty.")
Debug.WriteLine("Adding some items...")
My.Settings.MRU = tmpArrayList.Clone
ElseIf My.Settings.MRU.Count > 0 Then ' This part of the block will never thrown.
Debug.WriteLine("MRU setting is OK.")
Debug.WriteLine("Item Count: " & CStr(My.Settings.MRU.Count))
Threading.Thread.Sleep(Integer.MaxValue)
End If
Debug.WriteLine("Saving any changes")
My.Settings.Save()
Debug.WriteLine("Updating any changes")
My.Settings.Reload()
Debug.WriteLine(String.Empty)
Debug.WriteLine("****************************************")
Debug.WriteLine("Checking again the MRU setting status in...")
For Count As Integer = 1 To 3
Debug.WriteLine(CStr(Count) & New String("."c, Count))
Threading.Thread.Sleep(TimeSpan.FromSeconds(1))
Next
Debug.WriteLine("****************************************")
Debug.WriteLine(String.Empty)
Me.Test_Handler()
End Sub
End Class
Someone could teach me to understand why the ArrayList is not really saved, or show me how to solve this issue?.
UPDATE
Ok I've write this serializable class trying to solve this issue:
''' <summary>
''' A Class intended to use it as an Item for a MRU item collection that stores the item filepath, with additional info.
''' </summary>
<Serializable()>
Public Class MostRecentUsedItem
''' <summary>
''' Gets or sets the item filepath.
''' </summary>
''' <value>The file path.</value>
Public Property FilePath As String
''' <summary>
''' (Optionally) Gets or sets the item index.
''' </summary>
''' <value>The index.</value>
Public Property Index As Integer
''' <summary>
''' (Optionally) Gets or sets the item image.
''' </summary>
''' <value>The image.</value>
Public Property Img As Bitmap
''' <summary>
''' (Optionally) Gets or sets the item last-time open date.
''' </summary>
''' <value>The index.</value>
Public Property [Date] As Date
''' <summary>
''' (Optionally) Gets or sets the item tag.
''' </summary>
''' <value>The tag object.</value>
Public Property Tag As Object
End Class
Also I've write this helper function to help me in this issue:
''' <summary>
''' Determines whether an object can be XML serialized.
''' </summary>
''' <param name="Object">The object.</param>
''' <returns><c>true</c> if object is XML serializable; otherwise, <c>false</c>.</returns>
Private Function IsObjectSerializable(ByVal [Object] As Object) As Boolean
Using fs As New IO.FileStream(IO.Path.GetTempFileName, IO.FileMode.Create)
Dim Serializer As New Xml.Serialization.XmlSerializer([Object].GetType)
Try
Serializer.Serialize(fs, [Object])
Return True
Catch ex As InvalidOperationException
Return False
End Try
End Using
End Function
At the moment that I initialize the setting like this, it is serializable:
My.Settings.MRU = New ArrayList
At the moment that I add just a string, it still be serializable:
My.Settings.MRU.Add("test string")
But at the moment that I try to add my serializable class, or any other kind of datatype like a String()
, the ArrayList begins unserializable, Like this:
My.Settings.MRU.Add({"Collection", "Of", "Strings"})
Or like this else:
Dim MRUItem As New MostRecentUsedItem
MRUItem.FilePath = "C:\Test.ext"
My.Settings.MRU.Add(MRUItem)
...So the ArrayList contents are not preserved on the next run, can't be serialized.
I also tried to change the setting type from System.Collections.ArrayList
to System.Object
(desperately) so now I can do this, but the problem persist, I mean the collection is not saved on the next app run:
My.Settings.MRU = New List(Of MostRecentUsedItem)
Dim MRUItem As New MostRecentUsedItem
MRUItem.FilePath = "C:\Test.ext"
My.Settings.MRU.Add(MRUItem)
Since Application Settings serializes complex types as XML, you must make sure that the specific type can be serialized as XML before saving it.
You can test your data type with the following method:
This code fails to Serialize the ArrayList and returns the following message:
But if you try to store simple data type in the ArrayList, the Serialization will succeed
The same happens when you store data in the Application Settings, but the difference is that it doesn't return errors.
Useful links:
EDIT
Implementation using DataTable
Create a new Windows Forms Project, add a new setting called NewMRU in the Application Settings with a data type of System.Data.DataTable and try the following code.
If you want to use the Tag property (which I have omitted from the code since it's not serializable), you should split its values (Item, Value) as columns in the DataTable.