Recently I’ve been working on a Windows Phone app that comes with a good number of settings to implement.
The official examples that anyone can find online report a simple procedure.
Let’s say I want to implement the UserToken
setting, then I would have to do something like this:
[code language=”csharp”]
// Access the settings object
IsolatedStorageSettings appSettings = IsolatedStorageSettings.ApplicationSettings;
// Add settings
appSettings.Add("UserToken", "1a2b3c4d");
// Retrieve the value
string userToken = (string)appSettings["UserToken"];
// Set a new value
appSettings["UserToken"] = "5e6f7g8h";
[/code]
So I thought “well…that’s a lot of string identifiers to keep track of…”.
Obviously I started implementing some constant strings to use as identifiers, but given the current state of programming languages, it seemed a bit old fashioned.
I wanted to have a static class with properties linked to their respective settings, like you would have in other scenarios (see desktop applications and the settings designer), but without the encumbrance of hardcoded strings.
The solution I came up with makes use of Generics and a Compiler feature to access app settings using their property name.
So here’s how you would implement the UserToken
Property in a classic way:
[code language=”csharp”]
public static string UserToken
{
get
{
if (IsolatedStorageSettings.ApplicationSettings.Contains("UserToken"))
return (string) IsolatedStorageSettings.ApplicationSettings["UserToken"];
return "";
}
set
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
if (!settings.Contains("UserToken"))
settings.Add("UserToken", value);
else
settings["UserToken"] = value;
settings.Save();
}
}
[/code]
[hr]
That’s A LOT of stuff!!
After a bit of tweaking and little make-up, the above code became this:
[code language=”csharp”]
public static string UserToken
{
get { return GetGenericSetting<string>(); }
set { SetGenericSetting(value); }
}
[/code]
Isn’t it cool? 😀
Yes, but how does it work?
Both the GetGenericSetting
and SetGenericSetting
methods take an optional string parameter which defaults to the name of the calling property through the CallerMemberName attribute.
[box type=”info”]This means that whatever the property name is, the associated settings identifier will be the same.[/box]
Moreover, the use of generics allows both methods to be called by any property.
A return value type must be specified only for the get accessor (it could have been inferred, but it would have been an unnecessary overhead), while the setter gets its type from the value passed to the property.
This is how the two methods look like:
[code language=”csharp”]
// Gets a setting of type T from the IsolatedStorageSettings
// The item is identified by its key using the id parameter,
// which is automatically filled with the property name
private static T GetGenericSetting<T>([CallerMemberName] string id = "")
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(id))
// Explicit cast. You might want to use some try-catch here
return (T) IsolatedStorageSettings.ApplicationSettings[id];
// returns a default value for the specified type
// (null for classes, 0 for numerics and mixed for structs)
// see http://msdn.microsoft.com/en-us/library/xwth0h0d.aspx
// for more info
return default(T);
}
// Sets the value of a setting of type T from the IsolatedStorageSettings
private static void SetGenericSetting<T>(T value, [CallerMemberName] string id = "")
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
// If no corresponding key is found in the settings database,
// it must be created first
if (!settings.Contains(id))
settings.Add(id, value);
else
settings[id] = value;
// I like to keep track of things while I’m in Debug mode.
// This line will not be present if you compile in Release mode
Debug.WriteLine(id + " updated >> " + value);
// Save all the settings
settings.Save();
}
[/code]
[quote]What if I want to add Latitude
and Longitude
properties?[/quote]
There you go:
[code language=”csharp”]
public static double Latitude
{
get { return GetGenericSetting<double>(); }
set { SetGenericSetting(value); }
}
public static double Longitude
{
get { return GetGenericSetting<double>(); }
set { SetGenericSetting(value); }
}
[/code]
Easy right?
Then you would access such properties like you would normally do with static classes and their members
[code language=”csharp”]
Settings.UserToken = "1a2b3c4d";
Console.WriteLine(Settings.Latitude);
[/code]
Do you have some improvements to suggest?
Notice something wrong?
Please write it in the comments below!