views:

179

answers:

3

I've been storing collections of user settings in the Properties.Settings.Default object and using the Visual Studio settings designer (right-click on your project, click on Properties and then click on the Settings tab) to set the thing up. Recently, several users have complained that the data this particular setting tracks is missing, randomly.

To give an idea (not exactly how I do it, but somewhat close), the way it works is I have an object, like this:

class MyObject
{
    public static string Property1 { get; set; }
    public static string Property2 { get; set; }
    public static string Property3 { get; set; }
    public static string Property4 { get; set; }
}

Then in code, I might do something like this to save the information:

public void SaveInfo()
{
    ArrayList userSetting = new ArrayList();
    foreach (Something s in SomeCollectionHere) // For example, a ListView contains the info
    {
        MyObject o = new MyObject {
            Property1 = s.P1;
            Property2 = s.P2;
            Property3 = s.P3;
            Property4 = s.P4;
        };
        userSetting.Add(o);
    }
    Properties.Settings.Default.SettingName = userSetting;
}

Now, the code to pull it out is something like this:

public void RestoreInfo()
{
    ArrayList setting = Properties.Settings.Default.SettingName;

    foreach (object o in setting)
    {
        MyObject data = (MyObject)o;
        // Do something with the data, like load it in a ListView
    }
}

I've also made sure to decorate the Settings.Designer.cs file with [global::System.Configuration.SettingsSerializeAs(global::System.Configuration.SettingsSerializeAs.Binary)], like this:

    [global::System.Configuration.UserScopedSettingAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Configuration.SettingsSerializeAs(global::System.Configuration.SettingsSerializeAs.Binary)]
    public global::System.Collections.ArrayList SettingName
    {
        get {
            return ((global::System.Collections.ArrayList)(this["SettingName"]));
        }
        set {
            this["SettingName"] = value;
        }
    }

Now, randomly, the information will disappear. I can debug this and see that Properties.Settings.Default is returning an empty ArrayList for SettingName. I would really rather not use an ArrayList, but I don't see a way to get a generic collection to store in this way.

I'm about to give up and save this information using plain XML on my own. I just wanted to verify that I was indeed pushing this bit of .NET infrastructure too far. Am I right?

A: 

From your example I don't see anything incorrect about what your trying to do. I think the root of the problem your describing might be your assembly version changing? User settings do not auto-magically upgrade themselves (at least I couldn't get them to).

I can appreciate your plight, I went through this a few months ago. I coded up a UserSettings class that provided standard name/value pair collections (KeyValueConfigurationElement) under a named group heading something like the following:

<configSections>
  <section name="userSettings" type="CSharpTest.Net.AppConfig.UserSettingsSection, CSharpTest.Net.Library"/>
</configSections>
<userSettings>
  <add key="a" value="b"/>
  <sections>
    <section name="c">
      <add key="a" value="y"/>
    </section>
  </sections>
</userSettings>

Anyway see if this meets your needs or provides some insight into implementing a custom ConfigurationSection to allow what you need.

Oh yea, the code is here:

http://code.google.com/p/csharptest-net/source/browse/trunk/src/Library/AppConfig/

csharptest.net
Unfortunately, the assembly version isn't changing and the settings are already being upgraded when a new version comes out.
jasonh
A: 

When using the Settings feature with the User scope, the settings are saved to the currently logged in user's Application Data (AppData in Vista/7) folder. So if UserA logged in, used your application, and then UserB logged in, he wouldn't have UserA's settings loaded, he would have his own.

In what you're trying to accomplish, I would suggest using the XmlSerializer class for serializing an list of objects. The use is pretty simple:

To serialize it:

ArrayList list = new ArrayList();
XmlSerializer s = new XmlSerializer(typeof(ArrayList));
using (FileStream fs = new FileStream(@"C:\path\to\settings.xml", FileMode.OpenOrCreate))
{
    s.Serialize(fs, list);
}

To deserialize it:

ArrayList list;
XmlSerializer s = new XmlSerializer(typeof(ArrayList));
using (FileStream fs = new FileStream(@"C:\path\to\settings.xml", FileMode.Open))
{
    list = (ArrayList)s.Deserialize(fs);
}
nasufara
Only one user involved here, so that idea's out. I will most likely end up going with manual serialization and deserialization.
jasonh
A: 

I couldn't find an answer as to why these settings were disappearing and since I kept on happening, I ended up storing the complicated sets of settings separately in an XML file, manually serializing and deserializing them myself.

jasonh