Pages

Wednesday, July 4, 2012

CharmFlyout - Another Charming Custom Control

My goal is to make adding Settings Charm Flyouts to a C# Metro application as easy as possible. To that end, I created a custom control called CharmFlyout.

Posts in this series:

Install CharmFlyout from NuGet.org and add to your existing Metro application:

  1. Install the NuGet Package Manager if you have not already.
  2. Open your Metro application in Visual Studio
  3. Select Manage NuGet Packages from the Project menu.
  4. Click Online. Search for CharmFlyout. Click Install.

If you have a single page application with a MainPage.xaml, then edit MainPage.xaml to:

  1. Add the using:CharmFlyoutLibrary.
  2. Add the CharmFlyout custom control.
  3. Add content to the CharmFlyout. In the example below, the content is a StackPanel.
MainPage.xaml
<Page
   x:Class="CharmDemoApp.MainPage"
   IsTabStop="false"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:local="using:CharmDemoApp"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   xmlns:cfo="using:CharmFlyoutLibrary"
   mc:Ignorable="d">
    <Grid>
        <cfo:CharmFlyout
           x:Name="cfoSettings"
           Heading="My Flyout"
           HeadingBackgroundBrush="#FF4E0000">
            <StackPanel>
                <TextBlock
                   FontSize="16">CharmFlyout by John Michael Hauck</TextBlock>
                <TextBlock
                   FontSize="16">For support:</TextBlock>
                <HyperlinkButton
                   Click="OnMailTo">support@bing.com</HyperlinkButton>
            </StackPanel>
        </cfo:CharmFlyout>
        <TextBlock
           VerticalAlignment="Center"
           HorizontalAlignment="Center"
           FontSize="25"
           Foreground="Blue">
                Swipe the right side of the screen to show the Settings Charm
                <LineBreak />
                <LineBreak />
                CharmFlyout Demo
                <LineBreak />
                By John Michael Hauck
            <TextBlock.Transitions>
                <TransitionCollection>
                    <EntranceThemeTransition
                       FromVerticalOffset="400"
                       FromHorizontalOffset="0" />
                </TransitionCollection>
            </TextBlock.Transitions></TextBlock>
    </Grid>
</Page>

The location of the CharmFlyout should be such that it occupies the entire MainPage.  That is, don’t embed it inside of a StackPanel or otherwise restrict its size.

Add the code-behind in MainPage.xaml.cs as shown here:

MainPage.xaml.cs
using System;
using Windows.UI.ApplicationSettings;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace CharmDemoApp
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            SettingsPane.GetForCurrentView().CommandsRequested += CommandsRequested;
        }

        private void CommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
        {
            args.Request.ApplicationCommands.Add(new SettingsCommand("s", "My Flyout", (p) => { cfoSettings.IsOpen = true; }));
        }
    }
}


That's it.  When you run your application, you will see "My Flyout" in the settings charm, and when you click “My Flyout”, this will fly out:

About

Here is a comparison of the CharmFlyout vs. the Permissions flyout:

ap

CharmFlyout binaries reside here: http://nuget.org/packages/charmflyout/

CharmFlyout source resides here: http://charmflyout.codeplex.com/

Further Reading

If you are developing an application based on Grid App where there is no MainPage, then consider reading: CharmFrame – Adding CharmFlyout to GridApps.

If you are supporting sub-flyouts (like the Accounts in the Mail application), then consider reading: CharmFlyout – Supporting sub-flyouts.

Please check out a wonderful tutorial written by Håkan Sjö Ballina titled, Windows 8 Charm Flyouts.

23 comments:

  1. When using a project with several pages, such as created from the grid template, how does one wire up the flyout?

    If I just add it to the first page, it will display on the left side on the other pages, and also add additional menu items to the charm each time one navigates back to the first page.

    ReplyDelete
  2. I solved this by moving the UI into a UserControl and the code into the LayoutAwarePage base class.
    Let me know if you are interested in the details.

    ReplyDelete
    Replies
    1. Martin, Thank you for raising the issue and providing a solution.
      I just posted about an alternative solution here:
      http://w8isms.blogspot.com/2012/07/charmframe-adding-charmflyout-to-grid.html.

      Delete
  3. Yes We are :) Can you provide an example app how did you do that?

    ReplyDelete
  4. Hi there,

    While playing around with the new SubFlyout functionality I noticed that light dismissing a SubFlyout is not working as expected.

    Light dismissing a SubFlyout only closes that SubFlyout. Other Flyouts that happen to be still open stay open. Unfortunately I couldn't find any Event indicating that a light dismiss had taken place, so I couldn't close the "parent" Flyout manually. Any help on the matter would be greatly appreciated.

    Regards
    Andreas R.

    ReplyDelete
    Replies
    1. Andreas, The behavior was modeled after the Metro mail application. In that application, closing a sub-flyout returns you to the the previous flyout. I did not realize performing a light dismiss on the flyout should close parent flyouts. I can look as adding this in the next day or two if you wish.

      Delete
    2. I checked the Mail application again and as far as I can tell the "Accounts" Flyout only seems to change its content when navigated from within (Click on add account -> choose type, Click on a particular Account -> edit details and Click on "GoBack" when the User is in one of those sub menus). However lightdismissing in any of these contexts brings the User directly back to the Mail application.

      The Pane for entering information about a new account is not light dismissable at all and probably not even a Popup. But when cancelled the user is taken back to the Mail app again.

      I hope I made myself more clear now.

      In order to "fix" (in my opinion) the behaviour of the CharmFlyouts I downloaded the source and tried to add Closed event to the CharmFlyout class. I tried to raise it whenever the IsOpen Property was set to false. But seemingly that doesn't happen on a light dismiss.
      Maybe it is possible to make the Closed event of the internal Popup visible and react on that.

      Regards
      Andreas R.

      Delete
    3. Andreas,

      I updated NuGet and CodePlex with changes to support this behavior. The new version no longer supports IsSubFlyout. Instead it requires that you set ParentFlyout.

      That is, replace this:
      IsSubFlyout="True"

      With this:
      ParentFlyout="{Binding ElementName=cfoSettings}">

      Maybe you would be so kind to verify the behavior is as you expect.

      Delete
  5. The new Version of CharmFlyouts works as expected.

    Having looked at the source code, you did it the same way I would have done it after sleeping over the problem one more time.

    SubSub{...}Flyouts also work as expected.

    Thank you for looking into it so fast.

    Regards
    Andreas R.

    ReplyDelete
    Replies
    1. Andreas,
      And thank you for notifying me of the issue, testing it out, reviewing the code and providing feedback. I also appreciate the the thank you. Take care.

      Delete
  6. how to add two flyouts like if i wanted to also add another flyout for about and privacy etc

    ReplyDelete
    Replies
    1. Hasnain,

      I believe what you are looking for has been done in the CharmDemoGridApp sample application I developed and posted at: http://charmflyout.codeplex.com/

      This application shows two items in the settings pane: "My About" and "My Settings". The "My About" opens a simple flyout, and the "My Settings" contains a nested sub-settings flyout.

      Look at these source files:
      CharmFlyoutLibrary/CharmDemoGridApp/MyCharmFlyouts.xaml
      CharmFlyoutLibrary/CharmDemoGridApp/MyCharmFlyouts.xaml.cs

      Let me know if this helps (or not).


      Delete
  7. A great plugin.

    I would like to add that for those struggling with the problem of CharmFlyout popping to the left after few navigations, you need to add the below code to "unregister" the flyout.

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
    SettingsPane.GetForCurrentView().CommandsRequested -= onCommandsRequested;
    base.OnNavigatedFrom(e);
    }

    Thank you.

    ReplyDelete
    Replies
    1. Thanks Pirate11! I will have to update the source to reflect this.

      Delete
    2. Welcome. Glad I could be of help. Keep up the great work. Thanks.

      Delete
  8. Is there a way to raise an event on the page when the flyout closes? Similar to the JS onafterhide event?

    ReplyDelete
    Replies
    1. See MainPage.xaml.cs in the CharmDemoApp.
      http://charmflyout.codeplex.com/SourceControl/changeset/view/19182#212825

      Relevant code:
      cfoSettings.IsOpenChanged += CfoSettingsIsOpenChanged;

      Delete
    2. I should have mentioned... I'm trying the example where the flyout is in a user control, and App.xaml.cs sets the rootFrame to a new CharmFrame.

      With the example above, I get how I could do it if the flyout was on the individual page itself, but not sure how to do it across multiple pages like this.

      Great control, BTW!

      Delete
  9. I seem to be having an issue with radio buttons not showing in your Flyout control - does anyone else experience this?

    I can set the foreground brush manually but that only shows the text and not the button itself.

    ReplyDelete
    Replies
    1. There are a couple of things you can do here. You could modify the template used by the radio buttons to change the colors that are referenced. You could override the theme colors. You could also set the background color of the flyout to one such that the radio buttons become visible. As you have discovered, the radio button controls are present, however, their style is preventing them from being seen.

      This link might help: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/jj709925.aspx

      It provides all the colors used by the radio button control for both the Light and Dark themes as well as what is contained in the default template.

      Delete
  10. I have a situation where I want to invoke the same flyout from either the settings charm or a button in the app, but I can't prevent the back button from call SettingsPane.Show() without setting a parent. How would you feel about somehow making this possible?

    ReplyDelete
  11. The Codeplex source has been updated to provide a property on the CharmFlyout called ReturnToParentOnBack. The default value is true. In your case, set it to false and the back button will close the flyout and not call SettingsPane.Show. The property will also work for sub-flyouts if you do not want the sub-flyout to go back to the parent flyout.

    ReplyDelete

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