【问题标题】:My.Settings does not save an ArrayListMy.Settings 不保存 ArrayList
【发布时间】:2014-07-29 05:05:14
【问题描述】:

我已经设置了这个空属性:

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

当然我也检查了这个选项:

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

为什么会这样?

我该如何解决这个问题?

更新:

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

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

答案似乎很好,但我对代码和执行步骤有点迷茫,所以有人可以解释那里解释的步骤,但请用人类可读的语言为我解释一下吗?

我已经验证 ArrayList 仍然在下一个应用程序运行中,是的,但我不确定我在做什么,因为如果 MemoryStream 包含旧的 ArrayList,那么我现在正在做的是分配 My .Settings.MRU 设置为包含更多 Arraylists 的 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)

【问题讨论】:

  • 我建议您使用文本文件或数据库来保存数据。
  • 谢谢,我知道如何实现您评论过的替代方案(ini 文件或 xml 数据库),但我熟悉 My.Settings 的用法,我想在这种情况下保留它,因为这个应用程序确实不需要操作文本文件来存储/加载用户设置,因为我没有尝试设置用户可以通过编辑文件来决定其值的设置,我只是想设置一个 MRU环境。正如我所说,我熟悉 MY.Settings 界面,但这是我第一次遇到这种问题,我想修复它而不是避免它。感谢您的评论。
  • 每个文件,也是一个数据库,任何人都可以更改。您可以选择隐藏路径,例如AppData
  • @Joiner 是的,我知道你是对的,但是使用 My.Settings 它已经在 AppData (Roaming) 文件夹中创建了一个文件,我们可以说“它对他的用户隐藏”避免了创建使用自定义对象(如我的 ArrayList 和所有可能受到威胁的对象)读取/写入配置文件的自定义实现。感谢您的评论!
  • 如果您想使用 my.settings - 添加字符串键并将 ArrayList 序列化为字符串,例如使用 Xmlserializtion。然后将其存储在 My.Settings

标签: .net vb.net winforms visual-studio-2013 my.settings


【解决方案1】:

如果您在 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 来解决问题,用文件流替换 Memory Stream 就可以完全摆脱对 My.Settings 的需要,让你可以将文件存储在任何你想要的地方,并且它不会因版本而改变,用户改变EXE 名称或其他任何名称,除非您更改上面的文件名公式。

对于不仅仅是 MRU ArrayList 的应用程序,您可以使用一个类来将所有设置存储到您想要的位置,就像设置一样。您只需要将类标记为<Serializable>。只需要一行代码来保存整个类,用一行代码来重构它。有一些限制,但并不难克服。

Private myNewSettings As New myNewSettingsClass
...

bf.Serialize(fs, myNewSettings)

myNewSettings = CType(bf.Deserialize(fs), myNewSettingsClass )

在其他情况下,您可以根据需要使用 XML 序列化程序或 ProtoBuf-NET。

您还可以在程序退出时自动保存新设置:转到项目属性 --> 应用程序 --> 单击查看应用程序事件。从左侧菜单中选择“应用程序事件”,从右侧事件菜单中选择ShutDown

Private Sub MyApplication_Shutdown(sender As Object, 
          e As EventArgs) Handles Me.Shutdown

   ' add your code to Save (above) here
End Sub

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

【讨论】:

  • 这是一个很酷的解决方案,但我真的很想知道并解决 My.Settings 的真正问题
  • 您链接到的“解决方案”没有按照您的想法进行。它使用一个新的设置类,当 VB 请求数据时,它使用 IFormatter 将二进制序列化数据返回给 VB,VB 再进行 XML 序列化。这根本不是一个修复方法,而是一种用更多代码完成上述工作的更粗略的方法。
  • 只是一个问题,我只是不能使用实例化 ArrayList 的“copyto”方法将内容复制到 My.Settings.MyArrayList 属性中,也许这会解决真正的问题?我已经尝试过了,但该方法需要一个数组(不是数组列表)你能帮我吗?
  • 查看此答案:stackoverflow.com/a/24112414/1070452 如果您没有默认条目,则正如您所指出的,您无法添加任何内容,因此它会失败。初始化一下应该就ok了……不过还是上面的更好。
  • 在您的原始代码中(在开始解决方法之前),使用 addrange:My.Settings.MRU.AddRange({"Hoover", "Ziggy", "Punkin"})。使用Add 会创建一个锯齿状数组 (count=1),然后在下一次自动或从 .Reload 中 isnt 在 MRU 中。使用 Add 只会在 MRU 中创建一个元素,它是这些值的字符串数组(不是您可能想要的)。 VS可能没有捕获到异常。经过多次测试,Add 永远无法正常工作,AddRange 始终有效,但如果没有默认值,您确实需要第一次初始化 MRU。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-22
  • 1970-01-01
  • 2012-08-15
  • 2014-08-06
  • 2011-04-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多