Diederik Krols

The XAML Brewer

A XAML Settings Panel for Windows 8 Metro

This article describes how to create a custom Settings Panel for a Windows 8 Metro app (Consumer Preview) using XAML and C#. It also describes a way to broadcast the new settings to the app's components. Apps written in JavaScript and HTML5 can make use of the SettingsFlyout control. There's a full sample demonstrating everything. XAML developers have no out-of-the-box settings control. They have to look very hard to find just a modest quickstart. This article is loosely based on that quickstart.

Here's a screenshot of the demo app:

The app settings are stored in an instance of a custom class: AppSettings. They will be displayed by a custom user control: AppSettingsPane. That control is shown in a Popup when the settings charm is activated or the 'Settings' button is hit.

Since app settings are general, all functionality is implemented in the App class itself. I used a partial class to isolate the responsibilities.

Here's the run time routine:

When the app starts, settings are initialized:

// TODO: get initial settings from local storage, skydrive, cloud, or whatever.
private AppSettings appSettings = new AppSettings { NumberOfBottles = 2 };

The app registers a command with the Settings Charm:

SettingsPane.GetForCurrentView().CommandsRequested += App_CommandsRequested;

When executed, that command adds a new hyperlink in the default settings panel:

When that hyperlink is clicked, the app creates an instance of the custom user control, and displays it in a Popup. The Popup is positioned at the place where the system settings panel was: on the right hand side, using the full height, and 346 pixels wide:

Here's the command structure - the full code is attached at the end of this article:

private void App_CommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
{
    SettingsCommand cmd = new SettingsCommand("SettingsId", "Preferences", (x) =>
    {
        // Create popup
        _settingsPopup = new Popup()
            {
                IsLightDismissEnabled = true,
                // ...
            };
        _settingsPopup.Closed += OnPopupClosed;
        // ...

        // Create settings pane
        AppSettingsPane appSettingsPane = new AppSettingsPane()
            {
                // ...
                DataContext = new AppSettings
                    {
                        NumberOfBottles = this.appSettings.NumberOfBottles,
                        UseGlass = this.appSettings.UseGlass
                    } // A copy of the settings, so app working screen bindings are not updated
            };

        // Hook settings pane in popup
        _settingsPopup.Child = appSettingsPane;

        // Display popup
        _settingsPopup.IsOpen = true;
    });

    // Make commands available in settings pane
    args.Request.ApplicationCommands.Add(cmd);
}

Note that the settings pane is bound to a copy of the app settings. That way the working screens are not continuously updated while changing the settings. The popup can be closed by hitting the back button on the settings pane (the arrow on top), or by tapping somewhere outside the settings pane (that's why the IsLightDismissEnabled property of the popup is set to true).

On closing the popup, the app's settings are updated and then broadcasted to all the relevant components. Using an event aggregator is a nice way of doing this. The following code uses a singleton instance of the event aggregator from the Caliburn Micro MVVM framework:

private void OnPopupClosed(object sender, object e)
{
    _settingsPopup.Closed -= OnPopupClosed;

    AppSettings newSettings = (_settingsPopup.Child as FrameworkElement).DataContext as AppSettings;
    if (newSettings != null)
    {
        // Update app settings
        this.appSettings = newSettings;

        // Broadcast the new settings
        EventAggregator.Instance.Publish(this.appSettings);
    }
}

Views, viewmodels, services and other components that are interested in app settings changes, just need to implement the IHandle interface and register themselves to the event aggregator:

public sealed partial class BlankPage : Page, IHandle<AppSettings>
{
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        // Subscribe
        EventAggregator.Instance.Subscribe(this);
    }

    public void Handle(AppSettings settings)
    {
 // Update
        this.SettingsGrid.DataContext = settings;
    }
}

Here's the source code of the sample app. It was written in Visual Studio 11 Express Beta for the Windows 8 Consumer preview: U2UConsult.Metro.SettingsSample.zip (343,44 kb)

Enjoy!

Comments (4) -

  • Tam Kitelinger

    2/7/2014 1:50:52 AM |

    Immigration Lawyers… the time to read or visit the content or sites we have linked to below the…

  • Michel

    2/28/2014 7:23:06 AM |

    This is a smart blog. I mean it. You have so much knowledge about this issue, and so much passion. You also know how to make people rally behind it, obviously from the responses. Youve got a design here thats not too flashy, but makes a statement as big as what youre saying. Great job, indeed.

  • Hana

    2/28/2014 8:00:13 AM |

    Keep 'em coming... you all do such a great job at such Concepts... can't tell you how much I, for one appreciate all you do!

  • Felicita

    2/28/2014 9:44:04 AM |

    Finally, an issue that I am passionate about. I have looked for information of this caliber for the last several hours. Your site is greatly appreciated.

Comments are closed