Dela via


Part 3: Add navigation and views (Windows Runtime apps using C++)

[ This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation ]

This part of the C++ tutorial series teaches how to add pages and navigation, arrange controls and content on a page, and adapt the page layout to different orientations and views. We're going to use the design tools in Visual Studio, but you can also create and modify a UI by typing XAML directly into the code editor.

The UI design for your Store app is about defining its pages, the navigation between the pages, and the layout of content and commands on each page. Navigation patterns can help you choose the best navigation pattern for your app.

Note  See the two primary navigation patterns (Flat navigation and Hierarchical navigation) in action as part of our App features, start to finish series.

 

Before you start...

Step 1: Add pages and navigation

In this tutorial, we go over the basics of creating a user interface in XAML. To learn these basics, you create in your HelloWorld app a simple photo viewer that enables the user to pick an image from the Pictures Library and then view the image and some info about the image file.

The first thing to do is add a new page and a way to get to it from the MainPage.

Add the photo viewer page

We start with the code from Manage app lifecycle and state.

To add a page

  1. In Solution Explorer, select the HelloWorld project, and then choose Project > Add New Item.

  2. In the Add New Item dialog box, under Visual C++ in the left pane, select Windows Store.

  3. In the center pane, select Basic Page.

  4. Name it "PhotoPage.xaml" .

  5. Choose the Add button. The XAML and code-behind files for your page are added to the project.

    Here's the Add New Item dialog box.

To change the app title

  1. In the new page, delete the Page.Resources node that holds the page-specific AppName resource. We want to use the shared app name that we defined in the previous tutorial.

  2. Select the TextBlock named pageTitle. In the Properties window, choose the button for the Properties view. ().

  3. In the Properties window, under Common, choose the property marker for the Text property. The property menu opens.

    Note  The property marker is the small box symbol to the right of a property value. In this case, the Text property marker is green to indicate that it's set to a resource.

     

  4. On the property menu, select Edit Resource. The Edit Resource dialog box opens.

  5. In the Edit Resource dialog box, change the value from "My Application" to "Hello, photo!".

  6. Choose the OK button.

    After you edit the resource, the Extensible Application Markup Language (XAML) for the resource definition in App.xaml is updated like this:

    <x:String x:Key="AppName">Hello, photo!</x:String>
    

    (If you prefer, you can just edit the XAML directly in the code editor.)

  7. Add a new basic page to the phone project. In the TitlePanel, delete the PageTitle TextBlock and change the Text property to the AppName static resource. The node now looks like this:

            <!-- TitlePanel -->
            <StackPanel Grid.Row="0" Margin="24,17,0,28">
                <TextBlock Text="{StaticResource AppName}" Style="{ThemeResource 
                TitleTextBlockStyle}" Typography.Capitals="SmallCaps"/>
            </StackPanel>
    

    The earlier change to the resource is now reflected in the phone design surface as well. It, too, says "Hello Photo!".

Add navigation

The XAML UI framework provides a built-in navigation model that uses Frames and Pages and works much like the navigation in a web browser. The Frame control hosts Pages, and has a navigation history that you can use to go forward and back through pages you've visited. You can also pass data between the pages.

In the first two tutorials, you saw the code in App.xaml.cpp that creates a Frame and navigates to MainPage when the app is started. Here, you add a similar command to MainPage to navigate to the new PhotoPage.

In a traditional desktop app, you might add a button to navigate from the main page to the new photo page. When you design a Store app, it's important to consider the placement of commands. Many commands are best kept off of the main content area so that the layout stays simple and elegant.

Store apps provide app bars so that you can group commands that don't have to appear all the time. A user can access the commands by swiping from the bottom edge of the screen (also the top edge in Windows Store apps), or by opening the shortcut menu. In a Windows store app, the top app bar is typically used for navigation. In the Windows Phone 8.1 app, we don't have a top app bar, so we'll use the bottom one.

To add a navigation app bar in Windows 8.1 (by using the Document Outline and Properties windows)

  1. In Solution Explorer, open MainPage.xaml.

  2. In the Document Outline window (Ctrl+Alt+T), expand the "pageRoot" element, and then open the shortcut menu for TopAppBar and choose Add CommandBar. We only use AppBar for complex layouts.

  3. In the Document Outline window, you now see a CommandBar node. Expand the node, and then open the shortcut menu for PrimaryCommands and choose Add AppBarButton. An AppBarButton is added to the CommandBar and is selected.

  4. Under Icon in the Properties window (F4), select "Pictures" on the Symbol drop-down list.

  5. Under Common in the Properties window, change the Label value from "AppBarButton" to "Pictures".

  6. Now choose the Events button ().

  7. Select the Click event at the top of the event list and name it "PhotoPageButton_Click".

    Here's the XAML that the tools produced for you:

    <Page.TopAppBar>
        <CommandBar>
            <AppBarButton Label="Pictures" Icon="Pictures" Click="PhotoPageButton_Click"/>
        </CommandBar>
    </Page.TopAppBar>
    
  8. Place the cursor in the event handler name and press F12 for Go To Definition. Add this code to the handler function:

    if (this->Frame != nullptr)
    {
        this->Frame->Navigate(TypeName(PhotoPage::typeid));
    }
    
  9. Now #include PhotoPage.xaml.h at the top of MainPage.xaml.cpp. (Just start typing and statement completion will help you finish the job.)

  10. Press F5 to build and run the app. To open the app bar, swipe from the top or bottom edge of the screen, or right-click the app.

To add a navigation app bar and button in Windows Phone 8.1 (by using the XAML editor)

  1. Open MainPage.xaml and after the Page.Resources closing tag, start typing "Page.Bot". Statement completion will offer BottomAppBar. Press Tab to accept it. Then, between the two BottomAppBar tags, use statement completion to add a CommandBar, and in the CommandBar add an AppBarButton. In the button's opening tag, use statement completion to add Icon="Pictures", Label= "Pictures". Start typing "Click=", let the smart tag create the event handler for you, and accept the name it proposes. (Unfortunately, user-provided names are not currently supported.) We want to call the event handler PhotoPageButton_Click, so now do a project-wide search and replace (Ctrl+Shift+H), and then rebuild (Ctrl+Shift+B).

     <Page.BottomAppBar>
            <CommandBar>
                <AppBarButton Icon="Pictures" Label="Pictures" Click="PhotoPageButton_Click"/>
            </CommandBar>
        </Page.BottomAppBar>
    
  2. Place the cursor in the event handler name and press F12 for Go To Definition. Add this code to the handler function:

    if (this->Frame != nullptr)
    {
        this->Frame->Navigate(TypeName(PhotoPage::typeid));
    }
    
  3. Now #include PhotoPage.xaml.h at the top of MainPage.xaml.cpp.

  4. Open the shortcut menu for the Windows Phone 8.1 project in Solution Explorer and choose Set as Startup Project. Press F5 to build and run the app. The first row of the app bar is already visible; choose the ellipses button at the right to expand it fully.

Step 2: Add controls and content to a page

Before we add content to the photo page, let's review some fundamental points about layout in XAML.

  • The XAML layout system supports both static and fluid layouts. In general, we recommend that you use a fluid layout and let the XAML rendering engine automatically resize and arrange the UI elements for different display sizes and orientations.

  • Most app content is organized into nested groups in Panel controls. The most common panels are Grid and StackPanel for fluid layouts, and Canvas for static layouts. You use a Grid to arrange content in rows and columns, and a StackPanel to arrange content vertically or horizontally. Both Grids and StackPanels can contain nested Grids and StackPanels. You use a Canvas when you want to control all aspects of positioning and sizing.

  • You can specify size and position of child elements such as TextBlocks, Image controls, ListViews, and so on, by setting properties such as HorizontalAlignment, VerticalAlignment, Margin, Padding, Width, Height, MinWidth/MaxWidth, and MinHeight/MaxHeight.

  • In a universal Windows app, the Windows 8.1 and Windows Phone 8.1 projects have their own UI pages because UI controls that look good on a large screen don't always looks as good on a small screen, and vice versa. However, although you might use different controls or layouts in your two projects, the general principles of layout apply to all Store apps. And in simple layouts like this app, the XAML for the two projects is very similar.

Add a layout grid (Windows 8.1)

Let's start by adding a content grid. It will have 3 rows. The first 2 have a fixed height, and the last row fills the remaining available space. We'll use the XAML designer tools, although you can produce the same XAML by typing directly into the editor.

To add a Grid panel to PhotoPage.xaml

    1. Open PhotoPage.xaml.

    2. Drag a Grid from the Toolbox to the design surface, in the middle of the page.

      The Grid is added to the page, and the designer sets some properties based on its best guess at the layout you want. A blue highlight appears around the Grid to indicate that it's now the active object.

    3. With the new Grid still selected, press F4 to show the Properties window, and in the Name text box, enter "contentRoot" as the name of the Grid.

  1. Choose the property marker for each of the following Grid properties, and then choose Reset: Width, Height, HorizontalAlignment, VerticalAlignment, and Margin.

  2. Under Layout, set both the left Margin and the bottom Margin to "120" for the Windows app. For the Windows Phone 8.1 app set each margin to 20.

  3. In the designer, dotted lines known as grid rails appear along the top and left sides of the Grid. To add a row, move the pointer over the left grid rail. The pointer changes to an arrow that has a plus (+) sign, and an orange line shows where the row will be added.

  4. Click anywhere on the left grid rail to add a row.

  5. Repeat the previous step to add another row to the Grid.

    There are now 3 rows in the Grid. When the pointer is over the grid rail, a small fly-out appears so that you can use it to select sizing options and adjust the row Height property.

  6. Move the pointer over the grid rail in the first row until the fly-out appears.

  7. Choose the down-arrow button to open the menu and then choose Pixel.

  8. Move the pointer over the grid rail again, and then in the fly-out, select the number value.

  9. Type "50" and press Enter to set the Height property to 50 pixels.

  10. Repeat steps 9-12 to set the second row Height to 70 pixels.

    The last row is set to the default value of "1*" (1 asterisk), which means it will use the remaining available space.

Now, let's look at the XAML that's produced by our Grid settings:

<Grid x:Name="contentRoot" Grid.Row="1" Margin="120,0,0,120">
    <Grid.RowDefinitions>
        <RowDefinition Height="50"/>
        <RowDefinition Height="70"/>
        <RowDefinition/>
    </Grid.RowDefinitions>
</Grid>

Notice how rows are defined in this Grid, and then notice this setting in the opening Grid tag: Grid.Row="1". This Grid attribute is a reference to the parent grid. Remember that the Grid we just added is nested in the root Grid for the page. The Grid.Row attribute specifies which row of the parent Grid a control is placed in. The row and column numbering is zero-based, so "1" is actually the second row of the parent Grid. If you look at the XAML, notice that the first row, Row 0, is occupied by a grid that holds the page title and back button.

The designer sets the Grid row based on where you drop a XAML element when you add it. You can also manually modify it.

Add controls to the photo page (Windows 8.1)

Now you add controls to the Grid. You add a Button to get a picture from the Pictures library, an Image control to show the picture, and some TextBlock controls to show information about the picture file. You use StackPanels in the last grid row to arrange the Image and TextBlock controls.

To add controls to the page

  1. Add a "Get photo" button

    1. In the Document Outline window (Ctrl+Alt+T), select the "contentRoot" panel.
    2. Drag a Button control from the Toolbox to the first grid row.
    3. In the Properties window, choose the property marker for HorizontalAlignment and reset its properties, and then do the same for VerticalAlignment and Margin.
    4. Set the button's Content property (in the Common category) to "Get photo".
  2. Add an Image-name TextBlock

    1. With "contentRoot" selected in the Document Outline window, drag a TextBlock control from the Toolbox to the second grid row.

    2. In the Properties window, reset these TextBlock properties: HorizontalAlignment, VerticalAlignment, and Margin.

    3. Expand the Miscellaneous group and find the Style property.

    4. In the Style property menu, select System Resource > SubheaderTextBlockStyle.

  3. Add an Image control and Border

    1. With "contentRoot" selected in the Document Outline window, drag a StackPanel from the Toolbox to the last grid row.

    2. In the Properties window, reset these StackPanel properties: Width, Height, HorizontalAlignment, VerticalAlignment, and Margin.

    3. Set the Orientation property of the StackPanel to Horizontal.

    4. In the Name text box for the StackPanel, type "imagePanel", and then press Enter.

    5. With the StackPanel selected, drag a Border control from the Toolbox to the StackPanel.

    6. Under Brush in the Properties window, select Background.

    7. Select the solid-color brush style and then set the color value to "#FF808080".

    8. Repeat the preceding two steps for the BorderBrush property.

    9. Drag an Image control from the Toolbox to the Border.

    10. In the Name text box for the Image, type "displayImage", and then press Enter.

    11. In the Common property group, in the drop-down list in the Source property box, select "Logo.png".

    12. In the Document Outline window, select the Border that contains the Image and then, in the Layout group in the Properties window, reset the Width property.

  4. Add the image info

    1. Drag a TextBlock control from the Toolbox to the "imagePanel" StackPanel, to the right of the Image control.

      Here, you don't have to reset any layout properties because StackPanel and Grid handle the sizing of their child elements differently. For more info, see Quickstart: Adding layout controls.

    2. Select the StackPanel so that the TextBlock is no longer selected, and then drag another TextBlock to the the StackPanel. Do this two more times.

      Four TextBlock controls are now lined up horizontally to the right of the Image control.

    3. Select the first TextBlock and set its Text property to "File name:".

    4. Select the third TextBlock and set its Text property to "Path:".

The photo viewer UI for theWindows 8.1 app now looks like the following picture. It looks similar for the Windows Phone 8.1 app if you turn the design surface to landscape mode. Later we'll add XAML markup that will cause the layout to correctly adjust for portrait mode. The layout is nearly complete, but you still have to fix the appearance of the TextBlocks that show the picture info.

To fix the layout and formatting of the TextBlocks you added, you group the controls into a vertical StackPanel.

To group items into a StackPanel

  1. In the Document Outline window, select the first TextBlock in the "imagePanel" StackPanel.

  2. Press Shift and then click the last TextBlock in the group. The four TextBlock controls are now selected.

  3. Open the shortcut menu for the group of selected TextBlock controls, and then choose Group Into > StackPanel.

    A StackPanel is added to the page, and the four TextBlock controls are in it.

  4. Under Layout in the Properties window, set the Orientation property of the StackPanel to Vertical.

  5. Set the StackPanel left Margin to "20".

The last thing to do is to format the picture-info text. You use built-in styles for the text, and set some margins to create space between the elements.

To style the text

  1. In the Document Outline window, select the first TextBlock in the "imagePanel" StackPanel.
  2. Press Ctrl, and then select the third TextBlock in the group. Two TextBlock controls are now selected.
  3. Under Miscellaneous in the Properties window, on the menu for the Style property, choose System Resource > CaptionTextBlockStyle.
  4. Select the second and fourth TextBlock controls in the group.
  5. For these controls, set the Style property to System Resource > BodyTextBlockStyle. Set the left Margin property value to 10, and the bottom value to 30.

The complete XAML for the grid we added now looks like this:

 <Grid x:Name="contentRoot" Grid.Row="1" Margin="120,0,0,120">
            <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
                <RowDefinition Height="70"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Button Content="Get photo"  FontFamily="Global User Interface"/>
            <StackPanel x:Name="imagePanel" Grid.Row="2" Orientation="Horizontal">
                <Border BorderBrush="Gray" BorderThickness="1" Background="Gray">
                    <Image x:Name="displayImage" Source="Assets/Logo.png" Margin="0,-9,0,9" d:IsLocked="True"/>
                </Border>
                <StackPanel Margin="20,0,0,0">
                    <TextBlock TextWrapping="Wrap" Text="FileName:" Style="{StaticResource CaptionTextBlockStyle}"/>
                    <TextBlock x:Name="tbName" TextWrapping="Wrap" Text="TextBlock" Style="{StaticResource BodyTextBlockStyle}"/>
                    <TextBlock TextWrapping="Wrap" Text="Path:" Style="{StaticResource CaptionTextBlockStyle}"/>
                    <TextBlock x:Name="tbPath" TextWrapping="Wrap" Text="TextBlock" Style="{StaticResource BodyTextBlockStyle}"/>
                </StackPanel>
            </StackPanel>
            <TextBlock Grid.Row="1" TextWrapping="Wrap" Text="TextBlock"/>
        </Grid>

Press F5 to build and run the app. Navigate to the photo page. It now looks like this:

Add the layout grid and controls (Windows Phone 8.1)

The layout grid for the Windows Phone project is mostly the same with a few important changes. If you like, you can follow the same steps that you used for the Windows 8.1 project, and make the changes noted below.

Or if you would rather just get on with it, here's the XAML to replace the content grid that is already provided in PhotoPage.xaml in the Windows Phone project:

       <Grid x:Name="contentRoot" Grid.Row="1" Margin="20,0,10,10">
            <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Button Content="Get photo"/>
            <TextBlock Grid.Row="1" TextWrapping="Wrap" Text="TextBlock"/>
            <StackPanel x:Name="imagePanel" Grid.Row="2" Orientation="Vertical">
                <Border BorderBrush="Gray" BorderThickness="7" Background="Gray">
                    <Image x:Name="displayImage" Source="Assets/Logo.png"/>
                </Border>
                <StackPanel Margin="10,0,0,0">
                    <TextBlock TextWrapping="Wrap" Text="File name:" 
               Style="{ThemeResource BodyTextBlockStyle}"/>
                    <TextBlock TextWrapping="Wrap" Text="TextBlock" 
                Margin="10,0,0,0" Style="{StaticResource BodyTextBlockStyle}"/>
                    <TextBlock TextWrapping="Wrap" Text="Path:" 
               Style="{ThemeResource BodyTextBlockStyle}"/>
                    <TextBlock TextWrapping="Wrap" Text="TextBlock" 
               Style="{StaticResource BodyTextBlockStyle}" Margin="10,0,0,0"/>
                </StackPanel>
            </StackPanel>
        </Grid>

Notice these differences between the Windows XAML and the Windows Phone XAML:

  • The height of Row 1 in the Windows Phone UI is reduced to 50 pixels.
  • The margins are smaller in the Windows Phone UI.
  • The Windows Phone UI has no predefined CaptionTextBlockStyle, so we use BodyTextBlockStyle only. (You can create a caption style if you like.)

Step 3: Adapt the page layout to different orientations and views

So far, you've designed the Windows app to be viewed full screen in the landscape orientation, and the Windows Phone app to be viewed in portrait mode. But the UI in both platforms must adapt to different orientations. In addition, the Windows UI has to adapt to user-initiated window resizing.

Use different views in Visual Studio

To see what the app looks like in different views, you can use the Device window in Visual Studio. (The Device window is available only when a XAML page is active.) In the Device window, you can simulate various views, displays, and display options for your app. In this tutorial, you examine how to use the Orientation options. To view the UI at different screen resolutions, you use the Display options. A well-designed fluid layout adapts so that it looks good on different screens.

In the Windows project, let’s try the portrait orientation to see how the app looks.

To use different views in Visual Studio

  1. In the Device window, choose the Portrait button (). The designer changes to simulate the portrait view.

    This is what the app looks like when it's rotated to the portrait orientation, and the view is too narrow. You have to adjust the width of the app UI.

  2. Choose the Landscape button to switch back to the default view.

  3. Now switch to the Windows Phone project and switch the designer to landscape view:

Adjust the portrait view in Windows 8.1

Now, let's fix the portrait view in the Windows project.

When you change the StackPanel from Horizontal to Vertical, the Border and Image resize automatically. This is an example of fluid layout. The StackPanel lets its child elements stretch in the direction that it's oriented, and constrains them in the opposing orientation. Instead of setting the image to a fixed size, you let the layout panel arrange and size its child elements.

To adjust the portrait view

  1. In PhotoPage.xaml, add this block of XAML after the contentRootGrid element:

            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup>
                    <VisualState x:Name="Landscape">
                        <Storyboard>
                        </Storyboard>
                    </VisualState>
    
                    <VisualState x:Name="Portrait">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames 
                                Storyboard.TargetProperty="(StackPanel.Orientation)" 
                                Storyboard.TargetName="imagePanel">
                                <DiscreteObjectKeyFrame KeyTime="0">
                                    <DiscreteObjectKeyFrame.Value>
                                        <Orientation>Vertical</Orientation>
                                    </DiscreteObjectKeyFrame.Value>
                                </DiscreteObjectKeyFrame>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames 
                                Storyboard.TargetProperty="(FrameworkElement.Margin)" 
                                Storyboard.TargetName="imagePanel">
                                <DiscreteObjectKeyFrame KeyTime="0">
                                    <DiscreteObjectKeyFrame.Value>
                                        <Thickness>0,0,20,0</Thickness>
                                    </DiscreteObjectKeyFrame.Value>
                                </DiscreteObjectKeyFrame>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
    
  2. In the root Page opening tag, start typing "SizeChanged" and let Visual Studio create an event handler for you. Accept the default name, press F12 to go to the implementation, and then add this code:

    if (e->NewSize.Height / e->NewSize.Width >= 1)
    {
        VisualStateManager::GoToState(this, "Portrait", true);
    }
    else
    {
        VisualStateManager::GoToState(this, "Landscape", true);
    }
    
  3. Repeat the previous two steps for the Windows Phone 8.1 project.

For a Windows app, you can test different orientations, views, and resolutions by using the simulator in Visual Studio. To run your app in the simulator, first make sure that the Windows project is set as the startup project. Then select Simulator in the drop-down list next to the Start Debugging button on the Standard toolbar. For more information about testing the app in the simulator, see Running Windows Store apps from Visual Studio.

The app now looks like this in when you run it in the simulator in portrait orientation:

Now set the Windows Phone project as the startup project and press F5 to test it in the same way.

Summary

Congratulations! You're done with the third tutorial, which taught how to add new pages to your app and use the tools in Visual Studio to create a user interface.

See the code

Did you get stuck, or do you want to check your work? If so, see the complete code in the Hello World (C++) sample on Code Gallery.

Next steps

The next part of this tutorial series teaches how to access and work with files. See File access and pickers (C++).

For designers

Navigation patterns

Command patterns

Layout

Guidelines for back buttons

Guidelines for hub controls

Guidelines for app bars (Windows Store apps)

Making the app bar accessible

For developers (XAML)

Adding app bars (XAML)

Navigating between pages (XAML)

XAML Hub control sample

XAML AppBar control sample

XAML Navigation sample

Windows.UI.Xaml.Controls Hub class

Windows.UI.Xaml.Controls AppBar class

Windows.UI.Xaml.Controls CommandBar class