My.Settings не сохраняет ArrayList
-
20-12-2019 - |
Вопрос
Я установил это свойство пустоты:
Но после назначения нового ArrayList объект для свойства, свойство всегда остается пустым при каждом выполнении приложения.
В обработчике MyBase.Load event я вызываю этот метод просто для проверки этой проблемы:
sub blahblah handles mybase.load
me.CheckRecentFiles
end sub
Private Sub CheckRecentFiles()
Try
' This throws an object not referenced exception 'cause always is empty.
MsgBox(My.Settings.RecentFiles.Count)
Catch ex As Exception
MsgBox(ex.Message)
End Try
' Just for testing, if the collection is empty then I instance a new ArrayList
' and I assign it to the property and I save it and exit from the application.
' But even doing this the property is always empty in the next execution.
If My.Settings.RecentFiles Is Nothing Then
My.Settings.RecentFiles = New ArrayList
My.Settings.RecentFiles.Add({"test-Item1", "test-Item2", "Test-Item3"})
My.Settings.Save()
Application.Exit()
End If
End Sub
Как вы можете видеть в приведенном выше коде, я назначаю новый ArrayList с одной записью, но изменения вступают в силу только во время выполнения этого приложения. Если я выхожу из приложения, свойство снова становится пустым.
И, конечно же, я проверил этот вариант:
Но в любом случае в этом нет необходимости, поскольку я сохраняю настройки вручную в коде, так что...
Почему это происходит?
Как я могу решить эту проблему?
ОБНОВЛЯТЬ:
Я исследовал и кажется, что это известная проблема: массивы, ArrayLists и любые общие коллекции (типа) не могут быть сохранены с помощью my.settings (но, с другой стороны, StringCollection может)
Но в последнем ответе эта почта (ответ MemoryStream) объясняет простой способ навсегда сохранить изменения ArrayList в my.settings, а затем прочитать их при следующем запуске приложения.
Ответ кажется очень хорошим, но я немного запутался в коде и дальнейших действиях, поэтому кто-нибудь мог бы объяснить описанные там шаги, но на понятном мне языке, пожалуйста?
Я проверил, что ArrayList остается при следующем запуске приложения, да, но я не уверен в том, что делаю, потому что, если MemoryStream содержит старый ArrayList, то то, что я делаю сейчас, — это назначение My.Settings. Настройка MRU в виде списка массивов, который содержит больше Arraylists
вместо этого оригинальный ArrayList, содержащий String()
?, и вообще, как загрузить записи массива после сохранения настроек таким образом?
Вот что я пробовал из этого ответа:
' Create the ArrayList
Dim tmpArrayList = New System.Collections.ArrayList
tmpArrayList.Add({"test-Item1-1", "test-Item1-2", "Test-Item1-3"})
tmpArrayList.Add({"test-Item2-1", "test-Item2-2", "Test-Item2-3"})
' Serialize the arraylist entries:
Dim formatter As Runtime.Serialization.IFormatter =
New Runtime.Serialization.Formatters.Binary.BinaryFormatter
Dim ms1 As New IO.MemoryStream
formatter.Serialize(ms1, tmpArrayList)
' Save the ArrayList
My.Settings.MRU = New ArrayList(ms1.ToArray) ' I think it hould be like that?
' Load the ArrayList contained in My.Settings.MRU (no idea)
Решение
Если у вас есть данные в arrayList (или List или Collection) и вы ищете обходной путь в BinaryFormatter, нет веской причины также использовать My.Settings.Вы можете делать то же самое с помощью BinaryFormatter: просто сохраняете файл и выбираете имя.
Imports System.Runtime.Serialization.Formatters.Binary
Private MRUArrayList = New ArrayList
' file location
myFile = System.IO.Path.Combine(Environment.GetFolderPath(Environment. _
SpecialFolder.ApplicationData),
CompName,
ProgramName,
File)
Сохранить настройки:
Dim bf As New BinaryFormatter
Using fs As New FileStream(myFile, FileMode.OpenOrCreate)
bf.Serialize(fs, MRUArrayList )
End Using
Загрузить настройки:
' dont attempt for the first time run
If File.Exists(myFile) = False Then Return False
Dim bf As New BinaryFormatter
Using fs As New FileStream(myFile, FileMode.Open)
MRUArrayList = CType(bf.Deserialize(fs), ArrayList)
End Using
Если вам придется прибегнуть к BF в качестве обходного пути, замена потока памяти на файловый поток полностью избавит вас от необходимости в My.Settings, позволит хранить файл где угодно, и он не будет меняться в зависимости от версии, пользователь меняет имя EXE. или что-нибудь еще, если вы не измените формулу имени файла выше.
Для приложения, в котором есть не только MRU ArrayList, вы можете использовать вместо него класс для хранения всех настроек в нужном вам месте, как это делается в настройках.Вам просто нужно пометить класс как <Serializable>
.Остается одна строка кода для сохранения всего класса и одна строка для его воссоздания.Есть некоторые ограничения, но их нетрудно преодолеть.
Private myNewSettings As New myNewSettingsClass
...
bf.Serialize(fs, myNewSettings)
myNewSettings = CType(bf.Deserialize(fs), myNewSettingsClass )
В других ситуациях вы можете использовать сериализатор XML или ProtoBuf-NET, если это необходимо в конкретной ситуации.
Вы также можете автоматически сохранять новые настройки при выходе из программы:Идти к Свойства проекта -> Приложение -> Нажмите «Просмотр событий приложения»..В левом меню выберите «События приложения» и Неисправность из правого меню событий.
Private Sub MyApplication_Shutdown(sender As Object,
e As EventArgs) Handles Me.Shutdown
' add your code to Save (above) here
End Sub
Аналогичным образом вы можете настроить автоматическую загрузку их в Startup
событие.