Wensus Analytics

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 CallerMemberName to 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.