.net My.Settings不保存ArrayList

.net My.Settings不保存ArrayList,.net,vb.net,winforms,visual-studio-2013,my.settings,.net,Vb.net,Winforms,Visual Studio 2013,My.settings,我已设置此emptyness属性: 但是在为属性分配了一个新的ArrayList对象之后,在每次应用程序执行中,该属性始终为空 在MyBase.Load事件的处理程序中,我调用此方法,只是为了测试此问题: sub blahblah handles mybase.load me.CheckRecentFiles end sub Private Sub CheckRecentFiles() Try ' This throws an object not refe

我已设置此emptyness属性:

但是在为属性分配了一个新的ArrayList对象之后,在每次应用程序执行中,该属性始终为空

MyBase.Load事件的处理程序中,我调用此方法,只是为了测试此问题:

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分配一个条目,但是更改只在AppApplication执行期间生效,如果我退出应用程序,那么属性将再次变为空

当然,我也勾选了这个选项:

但无论如何,这是不必要的,因为我在代码中手动保存设置,所以

为什么会这样

我怎样才能解决这个问题

更新:

我已经调查过,似乎这是一个已知的问题,即my.settings无法保存数组、ArrayList和任何泛型集合(类型)(但另一方面,StringCollection可以)

但在的最后一个答案(MemoryStream答案)中,解释了一种将ArrayList的更改永久保存到my.settings,然后在下一次应用程序运行时读取的简单方法

答案似乎很好,但我对代码和要处理的步骤有点迷茫,所以有人可以用人类可读的语言为我解释这里解释的步骤,好吗

我已经验证了ArrayList在下一次应用程序运行时仍然存在,是的,但我不确定我在做什么,因为如果MemoryStream包含旧的ArrayList,那么我现在要做的是将My.Settings.MRU设置分配为包含更多
ArrayList
的ArrayList,而不是包含
String()
的原始ArrayList?,无论如何,以这种方式保存设置后如何加载数组项

这就是我从这个答案中尝试的:

' 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(或列表或集合)中有数据,并且您正在查看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
加载设置:

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的应用程序,您可以在其位置使用类将所有设置存储到您想要的位置,就像设置一样。您只需要将类标记为
。它保留一行代码来保存整个类,一行代码用来重新构建它。有一些限制,但并不难克服

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

同样,您可以让它在
启动
事件中自动加载它们。

我建议您使用文本文件或数据库来保存数据。谢谢,我知道如何实现您所评论的备选方案(ini文件或xml数据库)但我熟悉My.Settings的用法,我想在这种情况下保留它,因为这个应用程序确实不需要操纵文本文件来存储/加载用户设置,因为我没有尝试设置一个用户可以通过编辑文件来决定其值的设置,我只是尝试设置一个MRU设置。正如我所说,我熟悉我的.Settings界面,但这是我第一次遇到这种问题,我想解决它,而不是避免它。谢谢你的评论。每个文件,也是一个数据库,任何人都可以更改。您可以选择隐藏路径,例如
AppData
@Joiner是的,我知道您是对的,但是使用我的.Settings,它已经在AppData(Roaming)文件夹中创建了一个文件,我们可以说“它对用户是隐藏的”,从而避免了创建带有自定义对象的读取/写入配置文件的自定义实现(比如我的ArrayList和所有可能受到威胁的对象)。谢谢你的评论!如果你想使用my.settings-添加一个字符串键并将ArrayList序列化为一个字符串,例如使用Xmlserialiaztion。然后将其存储在my.settings中这是一个很酷的解决方案,但我真的想知道并解决我的.settings“解决方案”的真正问题你链接到的不是你所想的。它使用了一个新的设置类,当VB请求使用IFormatter将二进制序列化数据返回给VB,然后将其XML序列化时。这根本不是一个修复方法,而是一种更粗糙的方法,用更多的代码来完成上述操作。只是一个问题,我不能使用“copyto”实例ArrayList的方法将内容复制到My.Settings.MyArrayList属性中,这可能会解决实际问题?我已经尝试过,但该方法需要一个数组(而不是ArrayList)你能帮我吗?看看这个答案:如果你没有一个默认的条目,正如你所说的,它是零,你不能添加到零,所以它会失败。初始化它,它应该是好的…但是上面的更好。在你的原始代码中(在你开始解决之前),使用addrange:
My.Settings.MRU.addrange({“Hoover”,“Zigy”,“Punkin”})
。使用
Add
排序创建一个锯齿状数组(count=1),该数组在下次自动或从中不在MRU中。重新加载。使用Add仅在MRU中创建一个元素,该元素是这些值的字符串数组(可能不是您想要的)。可能有一个异常未被VS捕获。多次测试,添加从不起作用