Partilhar via


Using touch in a Windows Store business app using C# and XAML

[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]

From: Developing a Windows Store business app using C#, XAML, and Prism for the Windows Runtime

Previous page | Next page

Learn how to implement the tap, slide, swipe, pinch, and stretch touch interactions in a Windows Store business app. Data binding is used to connect standard Windows controls that use touch gestures to the view models that implement those gestures.

Download

After you download the code, see Getting started using Prism for the Windows Runtime for instructions on how to compile and run the reference implementation, as well as understand the Microsoft Visual Studio solution structure.

You will learn

  • How the Windows touch language was used in AdventureWorks Shopper.

Applies to

  • Windows Runtime for Windows 8.1
  • C#
  • Extensible Application Markup Language (XAML)

Making key decisions

Touch interactions in Windows use physical interactions to emulate the direct manipulation of UI elements and provide a more natural, real-world experience when interacting with those elements on the screen. The following list summarizes the decisions to make when implementing touch interactions in your app:

  • Does the Windows touch language provide the experience your app requires?
  • What size should your touch targets be?
  • When displaying a list of items, do the touch targets for each item need to be identically sized?
  • Should you provide feedback to touch interactions?
  • Should touch interactions be reversible?
  • How long should a touch interaction last?
  • When should you use static gestures versus manipulation gestures?
  • Do you need to design and implement a custom interaction?
    • Does the custom interaction require specific hardware support such as a minimum number of touch points?
    • How will the custom interaction be provided on a non-touch device?

Windows provides a concise set of touch interactions that are used throughout the system. Applying this language consistently makes your app feel familiar to what users already know, increasing user confidence by making your app easier to learn and use. Most apps will not require touch interactions that are not part of the Windows touch language. For more info see Touch interaction design.

There are no definitive recommendations for how large a touch target should be or where it should be placed within your app. However, there are some guidelines that should be followed. The size and target area of an object depend on various factors, including the user experience scenarios and interaction context. They should be large enough to support direct manipulation and provide rich touch interaction data. It is acceptable in some user experience scenarios for touch targets in a collection of items to be different sizes. For instance, when displaying a collection of products you could choose to display some products at a larger size than the majority of the collection, in order to draw attention to specific products. Touch targets should react by changing color, changing size, or by moving. Non-moving elements should return to their default state when the user slides or lifts their finger off the element. In addition, touch interactions should be reversible. You can make your app safe to explore using touch by providing visual feedback to indicate what will happen when the user lifts their finger. For more info see Guidelines for targeting and Guidelines for visual feedback.

Touch interactions that require compound or custom gestures need to be performed within a certain amount of time. Try to avoid timed interactions like these because they can often be triggered accidentally and can be difficult to time correctly. For more info see Responding to user interaction.

Static gestures events are triggered after an interaction is complete and are used to handle single-finger interactions such as tapping. Manipulation gesture events indicate an ongoing interaction and are used for dynamic multi-touch interactions such as pinching and stretching, and interactions that use inertia and velocity data such as panning. This data is then used to determine the manipulation and perform the interaction. Manipulation gesture events start firing when the user touches the element and continue until the user lifts their finger or the manipulation is cancelled. For more info see Gestures, manipulations, and interactions.

Only create a custom interaction and if there is a clear, well-defined requirement and no interaction from the Windows touch language can support your scenario. If an existing interaction provides the experience your app requires, adapt your app to support that interaction. If you do need to design and implement a custom interaction you will need to consider your interaction experience. If the interaction depends on items such as the number of touch points, velocity, and inertia, ensure that these constraints and dependencies are consistent and discoverable. For example, how users interpret speed can directly affect the functionality of your app and the users satisfaction with the experience. In addition, you will also have to design and implement an equivalent version of the interaction for non-touch devices. For more info see Responding to user interaction.

Important  To avoid confusing users, do not create custom interactions that duplicate or redefine existing, standard interactions.

 

[Top]

Touch in AdventureWorks Shopper

As previously described in Designing the UX, touch is more than simply an alternative to using a mouse. We wanted to make touch an integrated part of the app because touch can add a personal connection between the user and the app. Touch is also a natural way to enable users to browse and select products. In addition, we use Semantic Zoom to highlight how levels of related complexity can easily be navigated. With Semantic Zoom users can easily visualize high level content such as categories, and then zoom into those categories to view category items.

The AdventureWorks Shopper reference implementation uses the Windows touch language. We use the standard touch interactions that Windows provides for these reasons:

  • The Windows Runtime provides an easy way to work with them.
  • We don't want to confuse users by creating custom interactions.
  • We want users to use the interactions that they already know to explore the app, and not need to learn new interactions.

We also wanted AdventureWorks Shopper to be intuitive for users who use a mouse or similar pointing device. The built-in controls work as well with a mouse or other pointing device as they do with touch. So when you design for touch, you also get mouse and pen functionality. For example, you can use the left mouse button to invoke commands. In addition, mouse and keyboard equivalents are provided for many commands. For example, you can use the right mouse button to activate the app bar, and holding the Ctrl key down while scrolling the mouse wheel controls Semantic Zoom interaction. For more info see Guidelines for common user interactions.

The document Touch interaction design explains the Windows touch language. The following sections describe how we applied the Windows touch language in AdventureWorks Shopper.

[Top]

Tap for primary action

Tapping an element invokes its primary action. For example, on the GroupDetailPage, you tap on a product to navigate to the ItemDetailPage. The following diagram shows an example of the tap for primary action gesture in the AdventureWorks Shopper reference implementation.

Products are displayed on the GroupDetailPage in the AutoRotatingGridView custom control. This control displays a collection of items in a view state aware grid. This control is an ItemsControl, so it can contain a collection of items of any type. A benefit of using this control is that it derives from the GridView control that has touch capabilities built in.

To populate the AutoRotatingGridView custom control you can add objects directly to its Items collection or bind its ItemsSource property to a collection of data items. When you add items to a GridView-derived control they are automatically placed in a GridViewItem container that can be styled to change how an item is displayed.

AdventureWorks.Shopper\Views\GroupDetailPage.xaml

<awcontrols:AutoRotatingGridView
          Grid.Row="1"
          x:Name="itemsGridView"
          AutomationProperties.AutomationId="ItemsGridView"
          AutomationProperties.Name="Items In Category"
          TabIndex="1"
          Margin="0,0,0,0"
          Padding="120,0,30,50"
          ItemsSource="{Binding Items}"
          ItemTemplate="{StaticResource ProductTemplate}"
          MinimalItemTemplate="{StaticResource ProductTemplateMinimal}"
          SelectionMode="None"
          IsItemClickEnabled="True"
         Loaded="itemsGridView_Loaded">
    <interactivity:Interaction.Behaviors>
        <core:EventTriggerBehavior EventName="ItemClick">
            <awbehaviors:NavigateWithEventArgsToPageAction TargetPage="AdventureWorks.Shopper.Views.ItemDetailPage" EventArgsParameterPath="ClickedItem.ProductNumber"/>
        </core:EventTriggerBehavior>
    </interactivity:Interaction.Behaviors>
    <awcontrols:AutoRotatingGridView.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapGrid Orientation="Vertical" />
        </ItemsPanelTemplate>
    </awcontrols:AutoRotatingGridView.ItemsPanel>
    <awcontrols:AutoRotatingGridView.PortraitItemsPanel>
        <ItemsPanelTemplate>
            <WrapGrid Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </awcontrols:AutoRotatingGridView.PortraitItemsPanel>
    <awcontrols:AutoRotatingGridView.MinimalItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel HorizontalAlignment="Stretch" Margin="0,0,5,0"/>
        </ItemsPanelTemplate>
    </awcontrols:AutoRotatingGridView.MinimalItemsPanel>
    <awcontrols:AutoRotatingGridView.ItemContainerStyle>
        <Style TargetType="Control">
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            <Setter Property="Padding" Value="5,5,5,5"/>
        </Style>
    </awcontrols:AutoRotatingGridView.ItemContainerStyle>
</awcontrols:AutoRotatingGridView>

The ItemsSource property specifies that the AutoRotatingGridView will bind to the Items property of the GroupDetailPageViewModel class. The Items property is initialized to a collection of type ProductViewModel when the GroupDetailPage is navigated to.

The appearance of individual items in the AutoRotatingGridView is defined by the ItemTemplate property. A DataTemplate is assigned to the ItemTemplate property that specifies that each item in the AutoRotatingGridView will display the product subtitle, image, and description.

When a user clicks an item in the AutoRotatingGridView the app navigates to the ItemDetailPage. This behavior is enabled by setting the SelectionMode property to None, setting the IsItemClickEnabled property to true, and handling the ItemClick event. The EventTriggerBehavior binds the ItemClick event of the AutoRotatingGridView to the NavigateWithEventArgsToPageAction. So when a GridViewItem is selected the NavigateWithEventArgsToPageAction is executed, which navigates from the GroupDetailPage to the ItemDetailPage, passing in the ProductNumber of the ClickedItem to the ItemDetailPage. For more info about behaviors see Implementing behaviors to supplement the functionality of XAML elements.

For more info see Adding ListView and GridView controls. For more info about the AutoRotatingGridView custom control see Creating a custom GridView control that responds to layout changes.

[Top]

Slide to pan

The slide gesture is primarily used for panning interactions. Panning is a technique for navigating short distances over small sets of content within a single view. Panning is only necessary when the amount of content in the view causes the content area to overflow the viewable area. For more info see Guidelines for panning. One of the uses of the slide gesture in the AdventureWorks Shopper reference implementation is to pan among products in a category. For example, when you browse to a product, you can use the slide gesture to navigate to the previous or next product in the subcategory. The following diagram shows an example of the slide to pan gesture in AdventureWorks Shopper.

In AdventureWorks Shopper this gesture is implemented by the FlipView control. The FlipView control displays a collection of items, and lets you flip through them one at a time. The FlipView control is derived from the ItemsControl class, like the GridView control, and so it shares many of the same features. A benefit of using the FlipView control is that it has touch capabilities built in, removing the need for additional code.

To populate a FlipView you can add objects directly to its Items collection or bind its ItemsSource property to a collection of data items. When you add items to a FlipView they are automatically placed in a FlipViewItem container that can be styled to change how an item is displayed.

AdventureWorks.Shopper\Views\ItemDetailPage.xaml

<FlipView x:Name="flipView"
          AutomationProperties.AutomationId="ItemsFlipView"
          AutomationProperties.Name="Item Details"
          TabIndex="1"
          Grid.Row="1"
          ItemsSource="{Binding Items}"
          SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}"
          SelectedItem="{Binding SelectedProduct, Mode=TwoWay}">

The ItemsSource property specifies that the FlipView binds to the Items property of the ItemDetailPageViewModel class, which is a collection of type ProductViewModel.

For more info see Quickstart: Adding FlipView controls, How to add a flip view, Guidelines for FlipView controls.

[Top]

Swipe to select, command, and move

With the swipe gesture, you slide your finger perpendicular to the panning direction to select objects. The ability to use the swipe gesture depends upon the value of the SelectionMode property on the ListViewBase-derived control. A value of None indicates that item selection is disabled, while a value of Single indicates that single items can be selected using this gesture.

In the AdventureWorks Shopper reference implementation, the swipe gesture can be used to select items on the ChangeDefaultsFlyout, the CheckoutSummaryPage, and the ShoppingCartPage. When an item is selected on the ShoppingCartPage the bottom app bar appears with the app bar commands applying to the selected item. The following diagram shows an example of the swipe to select, command, and move gesture in AdventureWorks Shopper.

The IsSwipeEnabled property of the GridView control indicates whether a swipe gesture is enabled for the control. Setting IsSwipeEnabled to false disables some default touch interactions, so it should be set to true when these interactions are required. For example, when IsSwipeEnabled is false:

  • If item selection is enabled, a user can deselect items by right-clicking with the mouse, but cannot deselect an item with touch by using the swipe gesture.
  • If CanDragItems is true, a user can drag items with the mouse, but not with touch.
  • If CanReorderItems is true, a user can reorder items with the mouse, but not with touch.

The AdventureWorks Shopper reference implementation does not explicitly set the IsSwipeEnabled property, as its default value is true. The following code example shows how an item on the ShoppingCartPage can be selected with the swipe gesture.

AdventureWorks.Shopper\Views\ShoppingCartPage.xaml

<awcontrols:AutoRotatingGridView x:Name="ShoppingCartItemsGridView"
                               x:Uid="ShoppingCartItemsGridView"
                               AutomationProperties.AutomationId="ShoppingCartItemsGridView"
                               SelectionMode="Single"
                               Width="Auto"
                               Grid.Row="2"
                               Grid.Column="1"
                               Grid.RowSpan="2"
                               VerticalAlignment="Top"
                               ItemsSource="{Binding ShoppingCartItemViewModels}"
                               SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                               ItemTemplate="{StaticResource ShoppingCartItemTemplate}"
                               MinimalItemTemplate="{StaticResource ShoppingCartItemTemplateMinimal}"
                               Margin="0,0,0,0">
    <awcontrols:AutoRotatingGridView.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapGrid Orientation="Vertical"
                      ItemWidth="400" />
        </ItemsPanelTemplate>
    </awcontrols:AutoRotatingGridView.ItemsPanel>
    <awcontrols:AutoRotatingGridView.PortraitItemsPanel>
        <ItemsPanelTemplate>
            <WrapGrid Orientation="Horizontal"
                      ItemWidth="400" />
        </ItemsPanelTemplate>
    </awcontrols:AutoRotatingGridView.PortraitItemsPanel>
    <awcontrols:AutoRotatingGridView.MinimalItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel HorizontalAlignment="Left" />
        </ItemsPanelTemplate>
    </awcontrols:AutoRotatingGridView.MinimalItemsPanel>
    <Style TargetType="Control">
        <Setter Property="HorizontalAlignment"
                    Value="Stretch" />
        <Setter Property="HorizontalContentAlignment"
                    Value="Left" />
    </Style>
</awcontrols:AutoRotatingGridView>

The SelectedItem property of the AutoRotatingGridView custom control can be used to retrieve the item selected by the swipe gesture. Here the SelectedItem property performs a two-way binding to the SelectedItem property of the ShoppingCartPageViewModel class, which is shown in the following code example.

AdventureWorks.UILogic\ViewModels\ShoppingCartPageViewModel.cs

public ShoppingCartItemViewModel SelectedItem
{
    get { return _selectedItem; }
    set
    {
        if (SetProperty(ref _selectedItem, value))
        {
            
            if (_selectedItem != null)
            {
                // Display the AppBar 
                IsBottomAppBarOpened = true;

                IncrementCountCommand.RaiseCanExecuteChanged();
                DecrementCountCommand.RaiseCanExecuteChanged();
            }
            else
            {
                IsBottomAppBarOpened = false;
            }
            OnPropertyChanged("IsItemSelected");
        }
    }
}

When the SelectedItem property is set the IsBottomAppBarOpened property will be set to control whether or not to display the bottom app bar.

For more info about the AutoRotatingGridView custom control see Creating a custom GridView control that responds to layout changes.

[Top]

Pinch and stretch to zoom

Pinch and stretch gestures are not just for magnification, or performing optical zoom. The AdventureWorks Shopper reference implementation uses Semantic Zoom to help users navigate between large sets of data. Semantic Zoom enables you to switch between two different views of the same content. You typically have a main view of your content and a second view that allows users to quickly navigate through it. Users can pan or scroll through categories of content, and then zoom into those categories to view detailed information. The following diagram shows an example of the pinch and stretch to zoom gesture in AdventureWorks Shopper.

To provide this zooming functionality, the SemanticZoom control uses two other controls—one to provide the zoomed-in view and one to provide the zoomed-out view. These controls can be any two controls that implement the ISemanticZoomInformation interface. XAML provides the ListView and GridView controls that meet this criteria.

Tip  When you use a GridView in a SemanticZoom control, always set the ScrollViewer.IsHorizontalScrollChainingEnabled attached property to false on the ScrollViewer that's in the GridView's control template.

 

For the zoomed-in view, we display a MultipleSizedGridView custom control that binds to products that are grouped by sub-category. The MultipleSizedGridView also shows a title (the category) for each group.

AdventureWorks.Shopper\Views\HubPage.xaml

<awcontrols:MultipleSizedGridView x:Name="itemsGridView"
                                AutomationProperties.AutomationId="HubPageItemGridView"
                                AutomationProperties.Name="Grouped Items"
                                Margin="0,0,0,0"
                                Padding="120,0,40,46"
                                ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
                                ItemTemplate="{StaticResource AWShopperItemTemplate}"
                                MinimalItemTemplate="{StaticResource ProductTemplateMinimal}"
                                SelectionMode="None"
                                ScrollViewer.IsHorizontalScrollChainingEnabled="False"
                                IsItemClickEnabled="True"
                                Loaded="itemsGridView_Loaded">

The ItemsSource property specifies the items to be displayed by the MultipleSizedGridView. The groupedItemsViewSource static resource is a CollectionViewSource that provides the source data for the control.

AdventureWorks.Shopper\Views\HubPage.xaml

<CollectionViewSource x:Name="groupedItemsViewSource"
                      Source="{Binding RootCategories}"
                      IsSourceGrouped="true"
                      ItemsPath="Products" />

The RootCategories property on the HubPageViewModel specifies the data that is bound to the MultipleSizedGridView for the zoomed-in view. RootCategories is a collection of CategoryViewModel objects. The ItemsPath property refers to the Products property of the CategoryViewModel class. Therefore, the MultipleSizedGridView will show each product grouped by the category it belongs to.

For the zoomed-out view, we display a GridView that binds to filled rectangles for each category. Within each category the category title and number of products is displayed.

AdventureWorks.Shopper\Views\HubPage.xaml

<GridView x:Name="zoomedOutGrid"
          Padding="120,0,0,0"
          Foreground="White"
          AutomationProperties.AutomationId="HubPageGridView"
          ScrollViewer.IsHorizontalScrollChainingEnabled="False"
          ItemTemplate="{StaticResource AWShopperItemTemplateSemanticZoom}">

For more info about Semantic Zoom, see Adding SemanticZoom controls, and Guidelines for Semantic Zoom. For more info about the MultipleSizedGridView custom control see Creating a custom GridView control that displays items at multiple sizes. For more info about the AutoRotatingGridView custom control see Creating a custom GridView control that responds to layout changes.

[Top]

Swipe from edge for app commands

When there are relevant commands to display, the Adventure Works Shopper reference implementation displays the app bar when the user swipes from the bottom or top edge of the screen. Every page can define a navigation bar, a bottom app bar, or both. For instance, AdventureWorks Shopper displays both when you activate the app bars on the ShoppingCartPage. The following diagram shows an example of the swipe from edge for app commands gesture in AdventureWorks Shopper.

The AppBar and CommandBar controls are toolbars for displaying app-specific commands. AdventureWorks Shopper displays app bars on each page. The Page.TopAppBar property can be used to define the navigation bar, with the Page.BottomAppBar property being used to define the bottom app bar. Each of these properties will contain either an AppBar or CommandBar control that holds the app bar's UI components. In general, you should use the bottom app bar for contextual commands that act on the currently selected item on the page. Use the navigation bar for navigational elements that move the user to a different page.

AdventureWorks Shopper uses both AppBar and CommandBar controls. Bottom app bars are implemented by the CommandBar control, using AppBarButtons that define the commands that will appear on the app bar. A CommandBar must use AppBarButtons to display commands, and the default appearance of an AppBarButton is circular. Using a CommandBar control ensures that the commands will be laid out automatically, and resized when the app size changes.

AdventureWorks Shopper implements the navigation bar for each page as a user control named TopAppBarUserControl. This user control defines the Button controls that will appear in the navigation bar. Buttons are used to easily display non-circular commands, and must be placed inside an AppBar control.

AdventureWorks.Shopper\Views\TopAppBarUserControl.xaml

<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Height="125" Margin="0,15,0,0">
    <Button x:Name="HomeAppBarButton" x:Uid="HomeAppBarButton"
        AutomationProperties.AutomationId="HomeAppBarButton"
        Margin="5,0" 
        Style="{StaticResource HouseStyle}" 
        Content="Home"
        Height="125">
        <Interactivity:Interaction.Behaviors>
            <Core:EventTriggerBehavior EventName="Click">
                <Core:NavigateToPageAction TargetPage="AdventureWorks.Shopper.Views.HubPage"/>
            </Core:EventTriggerBehavior>
        </Interactivity:Interaction.Behaviors>
    </Button>
    <Button x:Uid="ShoppingCartAppBarButton" x:Name="ShoppingCartAppBarButton" 
        AutomationProperties.AutomationId="ShoppingCartAppBarButton"
        Margin="0,0,5,0" 
        Height="125"
        Style="{StaticResource CartStyle}" 
        Content="Shopping Cart">
        <Interactivity:Interaction.Behaviors>
            <Core:EventTriggerBehavior EventName="Click">
                <Core:NavigateToPageAction TargetPage="AdventureWorks.Shopper.Views.ShoppingCartPage"/>
            </Core:EventTriggerBehavior>
        </Interactivity:Interaction.Behaviors>
    </Button>
</StackPanel>

The VisualStateAwarePage.TopAppBar property on each page then uses the TopAppBarUserControl to define the navigation bar.

AdventureWorks.Shopper\Views\HubPage.xaml

<prism:VisualStateAwarePage.TopAppBar>
    <AppBar Style="{StaticResource AppBarStyle}"
            x:Uid="TopAppBar">
        <views:TopAppBarUserControl />
    </AppBar>
</prism:VisualStateAwarePage.TopAppBar>

The following diagram shows the navigation bar buttons for each page.

When an item on a page is selected, the app bar is shown in order to display contextual commands, by setting the IsOpen property on the CommandBar control. If you have contextual commands on an app bar, the mode should be set to sticky while the context exists so that the bar doesn't automatically hide when the user interacts with the app. When the context is no longer present, sticky mode can be turned off. This can be achieved by setting the IsSticky property on the CommandBar control.

For more information see Adding app bars, How to use an app bar in different views, Controls, and Guidelines for app bars.

[Top]

Swipe from edge for system commands

Users can swipe from the edge of the screen to reveal app bars and charms, or to display previously used apps. Therefore, it is important to maintain a sufficient distance between app controls and the screen edges. The following diagram shows an example of the swipe from edge for system commands gesture in AdventureWorks Shopper.

For more info see Laying out an app page.

[Top]