Over a million developers have joined DZone.
Platinum Partner

Windows Phone: How to Easily Store User Settings

· Mobile Zone

The Mobile Zone is brought to you in partnership with Strongloop and IBM.  Learn how IBM API Connect simplifies your API lifecycle for hybrid cloud with Node.js and Java.

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.




The Mobile Zone is brought to you in partnership with Strongloop and IBM.  Visually compose APIs with easy-to-use tooling. Learn how IBM API Connect provides near-universal access to data and services both on-premises and in the cloud.

Topics:

Published at DZone with permission of Mikael Koskinen , DZone MVB .

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}