\n
1:<\/span> public<\/span> class<\/span> ApplicationSettings : INotifyPropertyChanged<\/pre>\n<\/p>\n
2:<\/span> {<\/pre>\n<\/p>\n
3:<\/span> public<\/span> event<\/span> PropertyChangedEventHandler PropertyChanged;<\/pre>\n<\/p>\n
4:<\/span> <\/pre>\n<\/p>\n
5:<\/span> private<\/span> bool<\/span> _debugMode;<\/pre>\n<\/p>\n
6:<\/span> private<\/span> string<\/span> _albumNameFormat;<\/pre>\n<\/p>\n
7:<\/span> private<\/span> string<\/span> _extraFileExtensions;<\/pre>\n<\/p>\n
8:<\/span> private<\/span> bool<\/span> _automaticRun;<\/pre>\n<\/p>\n
9:<\/span> private<\/span> string<\/span> _galleryCreationSubCategory;<\/pre>\n<\/p>\n
10:<\/span> private<\/span> bool<\/span> _filenameOnlyCheck;<\/pre>\n<\/div>\n<\/div>\n
Properties created the standard way for INotifyPropertyChaged:<\/p>\n
\n
\n
1:<\/span> private<\/span> DateTime _nextUpdateCheck;<\/pre>\n<\/p>\n
2:<\/span> public<\/span> DateTime NextUpdateCheck<\/pre>\n<\/p>\n
3:<\/span> {<\/pre>\n<\/p>\n
4:<\/span> get { return<\/span> _nextUpdateCheck; }<\/pre>\n<\/p>\n
5:<\/span> set<\/pre>\n<\/p>\n
6:<\/span> {<\/pre>\n<\/p>\n
7:<\/span> if<\/span> (_nextUpdateCheck != value<\/span>)<\/pre>\n<\/p>\n
8:<\/span> {<\/pre>\n<\/p>\n
9:<\/span> _nextUpdateCheck = value<\/span>;<\/pre>\n<\/p>\n
10:<\/span> RaisePropertyChanged("NextUpdateCheck"<\/span>);<\/pre>\n<\/p>\n
11:<\/span> }<\/pre>\n<\/p>\n
12:<\/span> }<\/pre>\n<\/p>\n
13:<\/span> }<\/pre>\n<\/div>\n<\/div>\n
I wanted a predictable path for storing settings (so it would be easy to document and backup for users). I used the AssemblyCompany attribute and the AssemblyProduct attribute as the folder names:<\/p>\n
\n
\n
1:<\/span> internal<\/span> static<\/span> string<\/span> GetSettingsDirectory()<\/pre>\n<\/p>\n
2:<\/span> {<\/pre>\n<\/p>\n
3:<\/span> string<\/span> path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);<\/pre>\n<\/p>\n
4:<\/span> var attrs = Assembly.GetEntryAssembly().GetCustomAttributes(typeof<\/span>(AssemblyCompanyAttribute), false<\/span>);<\/pre>\n<\/p>\n
5:<\/span> if<\/span> (attrs.Length == 1)<\/pre>\n<\/p>\n
6:<\/span> {<\/pre>\n<\/p>\n
7:<\/span> path = Path.Combine(path, ((AssemblyCompanyAttribute)attrs[0]).Company);<\/pre>\n<\/p>\n
8:<\/span> <\/pre>\n<\/p>\n
9:<\/span> }<\/pre>\n<\/p>\n
10:<\/span> attrs = Assembly.GetEntryAssembly().GetCustomAttributes(typeof<\/span>(AssemblyProductAttribute), false<\/span>);<\/pre>\n<\/p>\n
11:<\/span> if<\/span> (attrs.Length == 1)<\/pre>\n<\/p>\n
12:<\/span> {<\/pre>\n<\/p>\n
13:<\/span> path = Path.Combine(path, ((AssemblyProductAttribute)attrs[0]).Product);<\/pre>\n<\/p>\n
14:<\/span> }<\/pre>\n<\/p>\n
15:<\/span> return<\/span> path; <\/pre>\n<\/p>\n
16:<\/span> }<\/pre>\n<\/div>\n<\/div>\n
In this WPF application, in the AssemblyInfo.cs file, the attributes are set as follows:<\/p>\n
\n
\n
1:<\/span> [assembly: AssemblyCompany("WiredPrairie.us"<\/span>)]<\/pre>\n<\/p>\n
2:<\/span> [assembly: AssemblyProduct("SnugUp"<\/span>)]<\/pre>\n<\/div>\n<\/div>\n
On my machine, that maps to this path:<\/p>\n
d:\\Users\\Aaron\\AppData\\Roaming\\WiredPrairie.us\\SnugUp\\<\/strong><\/p>\nLoading settings then is straightforward using JSON.NET:<\/p>\n
\n
\n
1:<\/span> public<\/span> static<\/span> ApplicationSettings Load(string<\/span> filename)<\/pre>\n<\/p>\n
2:<\/span> {<\/pre>\n<\/p>\n
3:<\/span> ApplicationSettings settings = null<\/span>;<\/pre>\n<\/p>\n
4:<\/span> var directory = GetSettingsDirectory();<\/pre>\n<\/p>\n
5:<\/span> var path = Path.Combine(directory, filename);<\/pre>\n<\/p>\n
6:<\/span> <\/pre>\n<\/p>\n
7:<\/span> if<\/span> (File.Exists(path))<\/pre>\n<\/p>\n
8:<\/span> {<\/pre>\n<\/p>\n
9:<\/span> string<\/span> fileData = File.ReadAllText(path);<\/pre>\n<\/p>\n
10:<\/span> try<\/span><\/pre>\n<\/p>\n
11:<\/span> {<\/pre>\n<\/p>\n
12:<\/span> settings = JsonConvert.DeserializeObject<ApplicationSettings>(fileData, new<\/span> JsonSerializerSettings { });<\/pre>\n<\/p>\n
13:<\/span> }<\/pre>\n<\/p>\n
14:<\/span> catch<\/span> { }<\/pre>\n<\/p>\n
15:<\/span> }<\/pre>\n<\/p>\n
16:<\/span> if<\/span> (settings == null<\/span>)<\/pre>\n<\/p>\n
17:<\/span> {<\/pre>\n<\/p>\n
18:<\/span> settings = new<\/span> ApplicationSettings();<\/pre>\n<\/p>\n
19:<\/span> SetDefaults(settings);<\/pre>\n<\/p>\n
20:<\/span> \/\/ initialize settings once<\/span><\/pre>\n<\/p>\n
21:<\/span> Save(settings, filename);<\/pre>\n<\/p>\n
22:<\/span> }<\/pre>\n<\/p>\n
23:<\/span> return<\/span> settings;<\/pre>\n<\/p>\n
24:<\/span> }<\/pre>\n<\/div>\n<\/div>\n
In my code, if the settings file didn\u2019t exist or fails to serialize into something meaningful, a new settings file is created with a few defaults. (I haven\u2019t decided what to do when there\u2019s an exception when reading the file, hence the empty catch).<\/p>\n
Saving the settings is just as easy:<\/p>\n
\n
\n
1:<\/span> public<\/span> static<\/span> void<\/span> Save(ApplicationSettings settings, string<\/span> filename)<\/pre>\n<\/p>\n
2:<\/span> {<\/pre>\n<\/p>\n
3:<\/span> Debug.Assert(settings != null<\/span>);<\/pre>\n<\/p>\n
4:<\/span> var directory = GetSettingsDirectory();<\/pre>\n<\/p>\n
5:<\/span> var path = Path.Combine(directory, filename);<\/pre>\n<\/p>\n
6:<\/span> <\/pre>\n<\/p>\n
7:<\/span> JsonConvert.SerializeObject(settings);<\/pre>\n<\/p>\n
8:<\/span> <\/pre>\n<\/p>\n
9:<\/span> if<\/span> (!Directory.Exists(directory))<\/pre>\n<\/p>\n
10:<\/span> {<\/pre>\n<\/p>\n
11:<\/span> Directory.CreateDirectory(directory);<\/pre>\n<\/p>\n
12:<\/span> }<\/pre>\n<\/p>\n
13:<\/span> <\/pre>\n<\/p>\n
14:<\/span> var fileData = JsonConvert.SerializeObject(settings, Formatting.Indented, new<\/span> JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate });<\/pre>\n<\/p>\n
15:<\/span> try<\/span><\/pre>\n<\/p>\n
16:<\/span> {<\/pre>\n<\/p>\n
17:<\/span> using<\/span> (StreamWriter writer = File.CreateText(path))<\/pre>\n<\/p>\n
18:<\/span> {<\/pre>\n<\/p>\n
19:<\/span> writer.Write(fileData);<\/pre>\n<\/p>\n
20:<\/span> writer.Close();<\/pre>\n<\/p>\n
21:<\/span> }<\/pre>\n<\/p>\n
22:<\/span> }<\/pre>\n<\/p>\n
23:<\/span>