Windows Phone: How to Easily Store User Settings
Here’s a base class for Windows Phone apps which I’ve been using to store user settings. It wraps the IsolatedStorageSettings and it’s a slightly modified version of the SettingsStore-class included in the “A Case Study for Building Advanced Windows Phone Applications – Code Samples”. Here’s an example of how to use the base class (in a Windows Phone 8 app):
public class MySettingsStore : SettingsStore { public bool IsFirstAppStart { get { return this.GetValueOrDefault(true); } set { this.AddOrUpdateValue(value); } } public string FirstName { get { return this.GetValueOrDefault(""); } set { this.AddOrUpdateValue(value); } } }
The class can be used store more complex objects too, as long as they are serializable:
[DataContract] public class User { [DataMember] public string Name { get; set; } } public class MySettingsStore : SettingsStore { public List<User> Users { get { return this.GetValueOrDefault(new List<User>()); } set { this.AddOrUpdateValue(value); } } }
The GetValueOrDefault-method takes one parameter and this is the default value which is returned if no stored setting is found.
In your app you can store a setting using the following code:
var settingsStore = new MySettingsStore(); ... settingsStore.FirstName = this.FirstNameTextBox.Text;
And to read a setting (or the default value):
var settingsStore = new MySettingsStore(); ... this.FirstNameTextBox.Text = settingsStore.FirstName;
Here’s the full code for the base class SettingsStore. It uses the CallerMemberNameto automatically deduct the key for a setting.
using System; using System.Collections.Generic; using System.IO.IsolatedStorage; using System.Runtime.CompilerServices; namespace Adafy.Infra { public class SettingsStore { private readonly IsolatedStorageSettings isolatedStore; public SettingsStore() { this.isolatedStore = IsolatedStorageSettings.ApplicationSettings; } protected void AddOrUpdateValue(object value, [CallerMemberName]string key = "key") { var valueChanged = false; lock (this) { try { if (value == null) { // Nothing to remove if (!this.isolatedStore.Contains(key)) return; this.isolatedStore.Remove(key); this.Save(); } // If the new value is different, set the new value. if (this.isolatedStore[key] != value) { this.isolatedStore[key] = value; valueChanged = true; } } catch (KeyNotFoundException) { this.isolatedStore.Add(key, value); valueChanged = true; } catch (ArgumentException) { this.isolatedStore.Add(key, value); valueChanged = true; } if (valueChanged) { this.Save(); } } } protected T GetValueOrDefault<T>(T defaultValue, [CallerMemberName]string key = "key") { lock (this) { T value; try { value = (T)this.isolatedStore[key]; } catch (KeyNotFoundException) { value = defaultValue; } catch (ArgumentException) { value = defaultValue; } return value; } } private void Save() { try { this.isolatedStore.Save(); } catch (Exception) { return; } } } }
SettingsStore for Windows Phone 7
CallerMemberName isn’t available in Windows Phone 7. Because of this, each settings must provide an unique key:
public class MySettingsStore : SettingsStore { private const string FirstAppStartKey = "MyKey"; private const string FirstNameKey = "MyKey2"; public bool IsFirstAppStart { get { return this.GetValueOrDefault(true, FirstAppStartKey); } set { this.AddOrUpdateValue(value, FirstAppStartKey); } } public string FirstName { get { return this.GetValueOrDefault("", FirstNameKey); } set { this.AddOrUpdateValue(value, FirstNameKey); } } }
Here’s the full code for WP7 version of the SettingsStore, which is nearly identical to the one provided in Prism.
using System; using System.Collections.Generic; using System.IO.IsolatedStorage; using System.Runtime.CompilerServices; namespace Adafy.Infra { public class SettingsStore { private readonly IsolatedStorageSettings isolatedStore; public SettingsStore() { this.isolatedStore = IsolatedStorageSettings.ApplicationSettings; } protected void AddOrUpdateValue(object value, [CallerMemberName]string key = "key") { var valueChanged = false; lock (this) { try { if (value == null) { // Nothing to remove if (!this.isolatedStore.Contains(key)) return; this.isolatedStore.Remove(key); this.Save(); } // If the new value is different, set the new value. if (this.isolatedStore[key] != value) { this.isolatedStore[key] = value; valueChanged = true; } } catch (KeyNotFoundException) { this.isolatedStore.Add(key, value); valueChanged = true; } catch (ArgumentException) { this.isolatedStore.Add(key, value); valueChanged = true; } if (valueChanged) { this.Save(); } } } protected T GetValueOrDefault<T>(T defaultValue, [CallerMemberName]string key = "key") { lock (this) { T value; try { value = (T)this.isolatedStore[key]; } catch (KeyNotFoundException) { value = defaultValue; } catch (ArgumentException) { value = defaultValue; } return value; } } private void Save() { try { this.isolatedStore.Save(); } catch (Exception) { return; } } } }
The SettingsStore classes could be combined with the help of conditional compilation.