Monday, March 7, 2011

WPF/C#: Where should I be saving user preferences files?

Whats the recommended location, to save user preference files? Is there a recommmended method(or should I call it pattern) of dealing with user preferences?

Currently I use the path returned from typeof(MyLibrary).Assembly.Location as a default location to store files generated or required by the app.

EDIT: Found two related/interesting questions:

http://stackoverflow.com/questions/147533/best-place-to-save-user-information-xp-and-vista http://stackoverflow.com/questions/348022/whats-the-way-to-implement-save-load-functionality

EDIT #2: This is just a note for people like me who had never used settings before. Settings are pretty useful, but I had to do a whole bunch of digging to figure out what was going on (Coming from a python world, not something I am used too). Things got complicated as I wanted to save dictionaries and apparently they cant be serialized. Settings also seem to get stored in 3 different files depending on what you do, There is an app.config, user.config and a settings.setting file. So here are two more links that I found useful:

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/ddeaca86-a093-4997-82c9-01bc0c630138 http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/efe370dc-f933-4e55-adf7-3cd8063949b0/

I am going to try and conduct, a bit of a social experiment. I am going to "award" the answer to any kind soul out there who would merge all these bits of information from the links and the answers of Sailingjudo/Nir/Samuel below into a more "complete" answer. If nothing happens in a week, SailingJudo gets selected by default for putting me on the right track. Or maybe I should just turn this into a community wiki?...still have to find out what that is...stackoverflow n00b here. Stackoverflow rocks btw! Thanks to everyone for their contributions!

From stackoverflow
  • You can use the Application Settings easily enough.

    If you haven't done so before just right click on the project and choose Properties. Select the Settings tab. Make sure you chose "User" for the scope (otherwise the setting is read-only).

    The code to access this is simple:

    forms.Width = Application1.Properties.Settings.Default.Width;
    

    If you need to save it:

    Application1.Properties.Settings.Default.Width = forms.Width;
    Application1.Properties.Settings.Default.Save();
    

    In the sample above, Width is the custom setting name you define in the Settings tab and Application1 is the Namespace of your application.

    Edit: Responding to further questions

    You mentioned you wanted to store Dictionary objects in the Settings. As you discovered, you can't do this directly because Dictionary objects are not serializable. However, you can create your own serializable dictionary pretty easily. Paul Welzer had an excellent example on his blog.

    You have a couple of links which sort of muddy the situation a little. Your original question is where to save "User Preference Files". I'm pretty certain Microsoft's intention with the Settings functionality is exactly that... storing user skin preferences, layout choices, etc. It not meant as a generic repository for an application's data although it could be easily abused that way.

    The data is stored in separate places for a good reason. Some of the settings are Application settings and are read-only. These are settings which the app needs to function but is not specific to a user (for example, URIs to app resources or maybe a tax rate). These are stored in the app.config.

    User settings are stored in an obfuscated directory deep within the User Document/Settings folder. The defaults are stored in app.config (I think, can't recall for certain off the top of my head) but any user changes are stored in their personal folder. This is meant for data that changes from user to user. (By "user" I mean Windows user, not your app's user.)

    Hope this clarified this somewhat for you. The system is actually pretty simple. It might seem a little foreign at first but after a few days of using it you'll never have to think of it again... it just works.

    Klerk : when you say access code is: forms.Width = Application1.Properties.Settings.Default.Width; Does this mean it loads Width that was possibly saved in a previous session?
    Klerk : Btw thanks for the reply. Learnt something new here,
    Samuel : Yes, the little sample he provided will restore the previous width. If you're going to use it (along with height and position), make sure you have some checks to ensure the window is visible. Restoring the position is a bad feature for dual monitor users when they remove the second one.
    Sailing Judo : Yes... this sample was just the first thing that popped into my head. You can store almost anything in the settings, including arrays. I have a rather extreme app that stores a large deserialized List of objects.
  • When running as non-admin or on Vista you can't write to the "Program files" folder (or any sub folder of it).

    The correct location to store user preference is (replace MyCompanyName and MyApplicationName with the correct names, obviously)

    On disk:

    Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\MyCompanyName\\MyApplicationName"
    

    Or in the registry under the key:

     HKEY_CURRENT_USER\Software\MyCompanyName\MyApplicationName
    

    Those location are per-user and they work with non-admin user, several users using the same computer, fast user switching, terminal services and all the other ways people can interact with your software.

    If you need a common location for all users then:

    1. It will only work when the user run as an administrator
    2. It will not work reliably on Vista
    3. You have to take care of everything yourself (like two users running the application on the same computer at the same time via fast user switching).

    and the locations are:

    Environment.GetFolderPath(Environment.SpecialFolder.ApplicationCommonData) + "\\MyCompanyName\\MyApplicationName"
    

    Or in the registry under the key:

     HKEY_LOCAL_MACHINE\Software\MyCompanyName\MyApplicationName
    
    Klerk : Thanks Nir. Your first alternative sounds like what I am looking for.
    Scott Whitlock : I think your second one should be CommonApplicationData, not ApplicationCommonData.
  • You can use isolated storage. You can isolate by user, assembly and/or domain. http://msdn.microsoft.com/en-us/library/3ak841sy(VS.80).aspx http://msdn.microsoft.com/en-us/library/eh5d60e1(VS.80).aspx

  • I have found this seems to be the case:

    Environment.SpecialFolder.CommonApplicationData
    

    rather than Environment.SpecialFolder.ApplicationCommonData.

  • the following seems to be the best option:

    Application.UserAppDataPath
    

0 comments:

Post a Comment