Introduction
Because most of our Windows Phone 7 applications require a configuration page to allow users to make any adjustments to the application itself and as this task is
always a repetitive task that does not require any extra processing, I decided to create a simple application with a configuration page that is generated automatically,
that may be helpful to us Windows Phone 7 developers.
Background
Since some time ago, in programming, it is a standard to save the settings of your application in XML format.
I decided to use the XML format because it is very versatile and of course there are utilities
that generate classes from an XML schema, so it is very easy to save or retrieve these settings using the serialization classes in .NET.
Code explanation
XML schema
The following image shows the XML schema that is used to generate our configuration. As shown, a configuration must have a name and data type, may also contain XAML code if you don't want
to self-generate a control; or if the data type is defined as a string array, you must provide a list of string items.
I've used JDeveloper to create this XML schema since I consider it as one
of the best visual editors of XML schemas and also, because it is free. JDeveloper is a bit slow, so it is recommended
to have a decent hardware with a good CPU, enough memory, and if you have a solid-state hard disk, much better.
The assignment of a data type to the configuration setting helps in the auto-generation of the configuration controls: if the String
or Numeric
data type is set,
then a TextBox
is generated; if it is a Boolean
data type, it will generate a ToggleSwitch
, and if it is a StringArray
data type,
it will generate a ListPicker
control.
MVVM project
Our simple application consists of two pages: MainPage
and SettingsPage
, a data model that contains the XML schema, translation into code (XSD to class),
and a sample configuration file (settings.xml). In turn, this application follows the convention of Model-View-View-Model (MVVM Light) by Laurent Bugnion.
The project also has a reference to Isolated Storage Explorer for WP7, that is because
an application may require some tuning for the default configuration so that we can start with a pretty basic configuration and finalize with a configuration file (settings.xml tuned
and tested, which in turn will become the default configuration file once the application gets deployed into marketplace).
In our application, we have used trivial and meaningless settings if you like, but it will serve well enough for demonstration purposes.
Let's now see the code in detail.
<settings xmlns="http://www.inputstudiowp7.com/schemas">
<Setting Name="Use Location" Type="Boolean" Value="True"/>
<Setting Name="Providers" Type="StringArray" Value="Item 2">
<StringItem Value="Item 1"/>
<StringItem Value="Item 2"/>
<StringItem Value="Item 3"/>
</Setting>
<Setting Name="Nick Name" Type="String" Value="Undefined"/>
<Setting Name="Age" Type="Integer" Value="18"/>
</settings>
The main page only has a few properties of our main Model-View and a hyperlink to the settings page. And the settings page is an empty Grid
with self-generating
controls once the page is loaded.
Main Page
|
Settings Page
|
|
|
As for the self-generated controls in the settings page, when the loading of the page occurs, the code iterates through each of the settings and the input controls
are generated according to its type, and a TextBlock
is assigned as the label (Caption) and a numeric or text input scope if applicable. Once you leave the configuration page,
the settings are saved.
public partial class SettingsPage : PhoneApplicationPage
{
public MainViewModel model { get { return this.DataContext as MainViewModel; } }
public SettingsPage()
{
InitializeComponent();
this.Loaded += new System.Windows.RoutedEventHandler(Settings_Loaded);
}
void Settings_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
Grid grid = this.FindName("LayoutRoot") as Grid;
if (null != grid)
{
StackPanel spContent = new StackPanel();
foreach (Setting setting in model.Settings.Setting)
{
TextBlock tbCaption =
new TextBlock() { Text = string.Format("{0}",
setting.Name.Trim()), Margin = new Thickness(12, 0, 0, 0) };
switch (setting.Type)
{
case eDataType.Boolean:
ToggleSwitch tsOption = new ToggleSwitch()
{
Name = string.Format("ts{0}",
setting.Name.Replace(" ", string.Empty)),
Header = setting.Name
};
tsOption.SetBinding(ToggleSwitch.IsCheckedProperty,
new Binding("Value")
{ Mode = BindingMode.TwoWay, Source = setting });
spContent.Children.Add(tsOption);
break;
case eDataType.String:
case eDataType.Integer:
case eDataType.Decimal:
TextBox txtValue = new TextBox()
{
Name = string.Format("txt{0}",
setting.Name.Replace(" ", string.Empty)),
Height = 72,
MaxLength = 50,
TextWrapping = TextWrapping.NoWrap
};
txtValue.SetBinding(TextBox.TextProperty,
new Binding("Value") { Mode = BindingMode.TwoWay,
Source = setting });
txtValue.InputScope = new InputScope()
{
Names = { new InputScopeName() {
NameValue = (setting.Type.Equals(eDataType.String)
? InputScopeNameValue.Text
: InputScopeNameValue.Number) } }
};
spContent.Children.Add(tbCaption);
spContent.Children.Add(txtValue);
break;
case eDataType.StringArray:
ListPicker lpValue = new ListPicker()
{
Header = string.Format("{0}", setting.Name.Trim())
};
List<string> items = new List<string>();
foreach (StringItem item in setting.StringItem)
items.Add(item.Value);
lpValue.ItemsSource = items;
lpValue.SetBinding(ListPicker.SelectedItemProperty,
new Binding("Value")
{ Mode = BindingMode.TwoWay, Source = setting });
spContent.Children.Add(lpValue);
break;
}
}
grid.Children.Add(spContent);
}
}
protected override void OnNavigatedFrom(
System.Windows.Navigation.NavigationEventArgs e)
{
model.saveSettings();
base.OnNavigatedFrom(e);
}
}
As an extra, the application sends an email when a catastrophic failure occurs.
Points of interest
If you find this auto-generated settings page useful, the Visual Studio templates may be modified to include this page and setting the configuration items.
This is just a starting point for building a fully configurable settings page.
History
First version of this post. Here is my second post in CodeProject.