Prism for Windows Runtime: Creating and showing a Flyout using the FlyoutService class
This is the third post in a series that walk you through creating a simple Windows Store app using the Prism for Windows Runtime library. Please review the second post in the series for the steps necessary to create the basic MVVM style app based on MvvmAppBase.
You can get the latest source on CodePlex.
The following procedure shows how to create and show a Flyout by using the Microsoft.Practices.Prism.StoreApps library. You will discover how to use the FlyoutService class within a view model to show the Flyout, and how to add a SettingsCommand that will launch the Flyout from the Settings pane.
Complete the Creating a basic implementation of the MVVM pattern walk through from the previous post.
First let’s create a Flyout. Add a blank page named SignInFlyout to the Views folder.
The FlyoutService will use a default convention to look for Flyouts in the Views namespace where the name of the Flyout ends in “Flyout”.Add a TextBlock to the Grid control in the SignInFlyout page.
<Grid Background="White"> <TextBlock Text="Sign In!!!" Foreground="Black" /> </Grid>
Change the SignInFlyout class to derive from the FlyoutView base class in the Microsoft.Practices.Prism.StoreApps library. Also, specify the width in the constructor. The StandardFlyoutSize class is defined in the Microsoft.Practices.Prism.StoreApps library.
public sealed partial class SignInFlyout : FlyoutView { public SignInFlyout() : base(StandardFlyoutSize.Narrow) { this.InitializeComponent(); } }
Update the SignInFlyout.xaml file so that the SignInFlyout view extends the FlyoutView base class in the Microsoft.Practices.Prism.StoreApps library.
-
<Infrastructure:FlyoutView xmlns:Infrastructure="using:Microsoft.Practices.Prism.StoreApps" ... </Infrastructure:FlyoutView>
Next, let’s update the StartPage to show the SignInFlyout. Import the interfaces from the Microsoft.Practices.Prism.StoreApps namespace into the StartPageViewModel class.
using Microsoft.Practices.Prism.StoreApps.Interfaces;
Add a constructor to the StartPageViewModel class that takes a parameter of type IFlyoutService.
public StartPageViewModel(IFlyoutService flyoutService) { }
Notice that the StartPageViewModel class does not have a default constructor.
Run the app.
You will receive a MissingMethodException that indicates that there isn't a parameterless constructor defined for the StartPageViewModel object. This occurs because the ViewModelLocator uses its default convention to locate the StartPageViewModel. The ViewModelLocator then used its default view model factory (Activator.CreateInstance) to construct an instance of the view model. In order for this to work, the type being constructed must possess a default constructor.
Let’s provide the ViewModelLocator with a factory to create view model instances for the StartPage. Override the OnInitialize method in the App class to train the ViewModelLocator how to construct the StartPageViewModel instance.
protected override void OnInitialize(IActivatedEventArgs args) { ViewModelLocator.Register(typeof(StartPage).ToString(), () => new StartPageViewModel(FlyoutService)); }
The Register method takes a string representation of the view type, and a delegate that returns the view model. You will see that the StartPageViewModel instance is created with the FlyoutService property of the MvvmAppBase class being passed to its constructor. Now that the ViewModelLocator knows how to construct the view model for the StartPage, it will not follow its convention for the StartPage.
Add a Button to the StackPanel in StartPage that will show the SignInFlyout.
<StackPanel> <TextBlock Text="Hello World!!!" /> <TextBox Text="{Binding FirstName, Mode=TwoWay}" /> <Button Content="ShowFlyout" Command="{Binding SignInCommand}" /> </StackPanel>
Notice that the Button's Command property will be bound to a SignInCommand in the StartPageViewModel class.
Import the System.Windows.Input namespace into the StartPageViewModel class.
using System.Windows.Input;
Add the SignInCommand property to the StartPageViewModel class.
public ICommand SignInCommand { get; private set; }
The property has a private setter because it will only be set internally.
Set the SignInCommand property to an instance of a DelegateCommand that invokes the FlyoutService.
public StartPageViewModel(IFlyoutService flyoutService) { SignInCommand = new DelegateCommand(() => flyoutService.ShowFlyout("SignIn")); }
The DelegateCommand class, provided by the Microsoft.Practices.Prism.StoreApps library, is constructed with a delegate that will be invoked when the command is executed. Here, a lambda expression is specified that calls the ShowFlyout method of the FlyoutService class, passing the name of the Flyout.
Run the app.
Select the SignIn Button.
The SignInFlyout appears. Yeah!
Next, let’s add an item to the Settings pane that will also show the SignInFlyout. Stop the app and override the GetSettingsCharmActionItems method in the App class. This method will be called when the CommandsRequested event of the SettingsPane class is raised. Add a SettingsCharmActionItem to the Settings pane that will open the SignInFlyout.
protected override IList<SettingsCharmActionItem> GetSettingsCharmActionItems() { return new List<SettingsCharmActionItem>{ new SettingsCharmActionItem("Sign In", () => FlyoutService.ShowFlyout("SignIn"))}; }
The SettingsCharmActionItem class, provided by the Microsoft.Practices.Prism.StoreApps library, takes two constructor parameters. The first is a string title that will be displayed in the Settings pane. The second is an Action delegate that will be invoked when the user selects the “Sign In” item in the Settings pane.
Run the app. Invoke the charms menu by making a horizontal edge gesture, swiping left with a finger or pointing device from the right of the screen.
Select the Settings charm to display the Settings pane.
Select the “Sign In” item.
The SignInFlyout appears.
Next let’s integrate a dependency injection container into the app.
Comments
Anonymous
May 09, 2013
What if you have a global in App.xaml.cs, how can you access it from your flyout view model? Is there a more appropriate method to do this?Anonymous
May 10, 2013
What I would do is register your "global" as a service into the DI container. You can then inject the service instance into any view model using a constructor parameter, preferably using an interface that your "global" implements.Anonymous
May 10, 2013
This seems to create a new instance of the type passed to the container. What if the global is a constant connection to a socket for network communications? Is this still possible? ThanksAnonymous
May 10, 2013
Just use container.RegisterInstance(yourGlobalinstance); and the object instance you configured will be passed to anything that takes a dependency on it.Anonymous
May 12, 2013
This worked. Thanks again for the help.Anonymous
September 12, 2013
how can i register my ViewModel if my ViewModel have more than one parameter?