Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Automatic Generation of Settings Page

0.00/5 (No votes)
6 Sep 2011 1  
Automatically generate a Windows Phone 7 settings page.

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.

Settings-schema.JPG

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.

Solution.JPG

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).

Isolated-Storage-Explorer.JPG

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
MvvmSettings-Home.JPG MvvmSettings-SettingsPage.JPG

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here