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.