Pages

Wednesday, July 4, 2012

The Quest for a Settings Flyout

This week I was told by a Microsoft Store representative that, "If you want to use a flyout for your settings then use the standard SettingsFlyout which comes from the right side and has an integrated back button."

Posts in this series:

ap

App Settings Sample

The representative suggested I use the code from the App settings sample found here:
http://code.msdn.microsoft.com/windowsapps/App-settings-sample-1f762f49.

The app's description states "This sample demonstrates how to use the ApplicationSettings API and settings flyouts to integrate an app's settings UI with the Settings charm."  It was disappointing to discover that (in the C#/XAML version) nothing happens when you select one of the settings commands.  Well, nothing except that a text box on the main page displays "You selected the General settings command" or "You selected the Help settings command."

Quickstart: Adding app settings using XAML

In response upon hearing my dismay, the Microsoft Store representative replied: "This is a better example:
http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh872190.aspx"  Well, truth be told, it is a better example: It actually provides some form of flyout functionality.  Here are some of my comments (good and bad) about the code:

  1. The code is for Metro Consumer Preview, not Release Preview, so you have a bunch of brush names to update.
  2. It nicely shows that flyouts should either be 346 or 646 pixels wide.
  3. It uses a nice entrance transitions for the flyout.
  4. The layout is almost identical to the default "Permissions" flyout - which seems to be the gold standard.
  5. The touch area for the back button is only 30x30 (It should be 50x50 according to http://msdn.microsoft.com/en-us/library/windows/apps/hh465415).
  6. Rotating the display when the flyout is open causes very interesting (and wrong) behaviors.
  7. The code does not use a ContentPresenter for the content of the flyout.  This can wrongfully encourage copying/pasting of the same code.
  8. Since a UserControl cannot override PopUp, a lot of extra work is required to incorporate this into an application.
  9. The code-behind for the UserControl SimpleSettingsNarrow assumes it is encapsulated in a PopUp.
  10. The amount of code-behind required in MainPage.xaml.cs for displaying the flyout is almost obscene:
    1. The flyout and a PopUp are created and the flyout is embedded in the PopUp.
    2. Two event handers are wired to watch when the PopUp is closed and the current window is activated.
    3. The MainPage must close the Popup when it is Activated.
  11. If you have other reasons to monitor OnWindowActivated, the code gets even worse.

Do all this for a flyout?
void BlankPage_CommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
{
    SettingsCommand cmd = new SettingsCommand("sample", "Sound Options", (x) =>
    {
        _settingsPopup = new Popup();
        _settingsPopup.Closed += OnPopupClosed;
        Window.Current.Activated += OnWindowActivated;
        _settingsPopup.IsLightDismissEnabled = true;
        _settingsPopup.Width = _settingsWidth;
        _settingsPopup.Height = _windowBounds.Height;

        SimpleSettingsNarrow mypane = new SimpleSettingsNarrow();
        mypane.Width = _settingsWidth;
        mypane.Height = _windowBounds.Height;

        _settingsPopup.Child = mypane;
        _settingsPopup.SetValue(Canvas.LeftProperty, _windowBounds.Width - _settingsWidth);
        _settingsPopup.SetValue(Canvas.TopProperty, 0);
        _settingsPopup.IsOpen = true;
    });

    args.Request.ApplicationCommands.Add(cmd);
}

Callisto

It turns out Tim Heuer has also recently created a solution to the problem: https://github.com/timheuer/callisto.  Callisto is a nice attempt at providing those little needed tools for Metro C#/XAML development.  However, Callisto too suffers from an inability to handle screen rotations properly.  That may be easily fixed.  A bit more concerning are the many lines of code-behind required to display the SettingsFlyout.  For example, here is Tim's own code from SettingsSample.xaml.cs to open a single flyout.

Still too much code
private void BlankPage_CommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
{
    SettingsCommand cmd = new SettingsCommand("sample", "Sample Custom Setting", (x) =>
    {
        SettingsFlyout settings = new SettingsFlyout();
        settings.FlyoutWidth = (Callisto.Controls.SettingsFlyout.SettingsFlyoutWidth)Enum.Parse(typeof(Callisto.Controls.SettingsFlyout.SettingsFlyoutWidth), settingswidth.SelectionBoxItem.ToString());
        //settings.HeaderBrush = new SolidColorBrush(Colors.Orange);
        //settings.Background = new SolidColorBrush(Colors.Red);
        settings.HeaderText = "Foo Bar Custom Settings";

        BitmapImage bmp = new BitmapImage(new Uri("ms-appx:///Assets/SmallLogo.png"));

        settings.SmallLogoImageSource = bmp;

        StackPanel sp = new StackPanel();

        ToggleSwitch ts = new ToggleSwitch();
        ts.Header = "Download updates automatically";

        Button b = new Button();
        b.Content = "Test";

        sp.Children.Add(ts);
        sp.Children.Add(b);

        settings.Content = sp;

        settings.IsOpen = true;

        ObjectTracker.Track(settings);
    });

    args.Request.ApplicationCommands.Add(cmd);
}

I do have a lot of hope for Tim's library because the SettingsFlyout was developed as a custom control and the Generic.xaml appears to be very well written.  I think it is only a matter of time before Callisto's SettingsFlyout takes a nicer shape.

Onward

In any case, these discoveries are enough to motivate me to see if I can build a more charming flyout.

Consider reading
CharmFlyout - Another Charming Custom Control next.

10 comments:

  1. FWIW the "too much code" here is just test code. The minimum is to set the header/icon and content (my test app builds up the content in code which isn't typical and you would likely just use your own UserControl here). The ObjectTracker is also just test code.

    ReplyDelete
    Replies
    1. With SettingsFlyout, it is not quite as simple as just setting the header/icon and content. You also need to actually create the SettingsFlyout and set the width in code. It would be better to define this all in XAML. Even though CharmFlyout only requires setting a bool (cfoSettings.IsOpen = true), I think that is still too much. Binding would be a better solution. In short, it all belongs in XAML. In any case, creating UI elements in code-behind is never my first choice - sometime my second though.

      Delete
  2. Unfortunatelly it's not working good with WebView control.
    Just try to replace to view another appearance of the webview's "airspace issue".

    ReplyDelete
    Replies
    1. "Just try to replace TextBlock in the MainPage.xaml (CharmDemoApp project) with WebView Margin="50" Source="http://www.bing.com"/ to view another appearance of the webview's "airspace issue"."

      Delete
    2. I'm confused... You want to place a WebView in your settings charm flyout? Why? You also say a margin of 50 - why so thick when the flyout is only 346 wide to begin with? Finally, if we all know that WebView already has an "airspace issue", why discuss it here?

      Delete
    3. >> You want to place a WebView in your settings charm flyout? Why?

      no, I want to place webview on main window (instead of textblock in your example)

      will upload screenshot in a minute

      Delete
    4. here it is:
      https://skydrive.live.com/redir?resid=F9BAA460D82E7C33!264&authkey=!AByysj9RevwWpaM

      Delete
    5. WebView's "airspace" issue seems to be a real mess. I cannot offer anything beyond what is written here: http://stackoverflow.com/questions/10639493/how-to-solve-z-index-of-webview-control-in-xaml-in-metro-style-app

      I suppose beyond using a brush, you could always collapse your WebView. Sorry I cannot be of more help.

      It looks like MSFT states "There are no planned changes for Windows 8 regarding WebView pertaining to [the airspace issue]..."
      - http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/23a235a2-b0a3-4161-bc74-c42289c61264

      Delete
  3. Great article!
    Is os good when we find good resources!

    I think the CharmFlyout can have an image in the header. I changed it for my applications.

    ReplyDelete
  4. Hi,

    I want to use the same Flyout control to be displayed from Left Side of the screen instead of Right.. Is there anyway to achieve this..Please let me know if any effort i need to be done

    Thanks in advance
    Puneeth

    ReplyDelete

Note: Only a member of this blog may post a comment.