コレクションとリストのコンテキスト コマンドの実行Contextual commanding for collections and lists

多くのアプリに、リスト、グリッド、ツリーの形で、ユーザーが操作できるコンテンツのコレクションが含まれています。Many apps contain collections of content in the form of lists, grids, and trees that users can manipulate. たとえば、ユーザーは、項目の削除、名前の変更、フラグ付け、更新ができる可能性があります。For example, users might be able to delete, rename, flag, or refresh items. この記事では、どのような種類の入力でも、最善のエクスペリエンスが得られるように、そのような操作をコンテキスト コマンドを使って実装する方法を説明します。This article shows you how to use contextual commands to implement these sorts of actions in a way that provides the best possible experience for all input types.

重要な API:ICommand インターフェイスUIElement.ContextFlyout プロパティINotifyPropertyChanged インターフェイスImportant APIs: ICommand interface, UIElement.ContextFlyout property, INotifyPropertyChanged interface

各種入力方法で、お気に入りのコマンドを実行する

あらゆる種類の入力に対応するコマンドを作成するCreating commands for all input types

ユーザーはさまざまなデバイスや入力方法を使って Windows アプリを操作できるため、アプリでは入力方法に依存しないコンテキスト メニューと、各種入力方法専用のアクセラレータの両方でコマンドを公開する必要があります。Because users can interact with a Windows app using a broad range of devices and inputs, your app should expose commands though both input-agnostic context menus and input-specific accelerators. 両方を含めることで、入力方法やデバイスの種類に関わらず、コンテンツに対してコマンドをすばやく呼び出すことができます。Including both lets the user quickly invoke commands on content, regardless of input or device type.

次の表に、いくつかの典型的なコレクションのコマンドと、これらのコマンドを公開する方法を示します。This table shows some typical collection commands and ways to expose those commands.

コマンドCommand 入力方法を問わないInput-agnostic マウス アクセラレータMouse accelerator キーボード アクセラレータKeyboard accelerator タッチ アクセラレータTouch accelerator
項目の削除Delete item ショートカット メニューContext menu ホバー ボタンHover button DEL キーDEL key スワイプして削除Swipe to delete
フラグの設定Flag item ショートカット メニューContext menu ホバー ボタンHover button Ctrl + Shift + GCtrl+Shift+G スワイプしてフラグを設定Swipe to flag
データの更新Refresh data ショートカット メニューContext menu なしN/A F5 キーF5 key 引っ張って更新Pull to refresh
お気に入りに追加Favorite an item ショートカット メニューContext menu ホバー ボタンHover button F、Ctrl + SF, Ctrl+S スワイプしてお気に入りに追加Swipe to favorite
  • 通常は、特定の項目に対するすべてのコマンドをその項目のコンテキスト メニューから利用できるようにします。In general, you should make all commands for an item available in the item's context menu. コンテキスト メニューには、入力の種類にかかわらず、ユーザーがアクセスでき、ユーザーが実行できるコンテキスト コマンドの全部を含めてください。Context menus are accessible to users regardless of input type, and should contain all of the contextual commands that user can perform.

  • 頻繁にアクセスするコマンドについては、入力アクセラレータを使うことを検討してください。For frequently accessed commands, consider using input accelerators. 入力アクセラレータを使うと、ユーザーの入力デバイスに応じて、すばやく操作を実行できます。Input accelerators let the user perform actions quickly, based on their input device. 次のような入力アクセラレータがあります。Input accelerators include:

    • スワイプして操作 (タッチ アクセラレータ)Swipe-to-action (touch accelerator)
    • 引っ張ってデータを更新 (タッチ アクセラレータ)Pull to refresh data (touch accelerator)
    • キーボード ショートカット (キーボード アクセラレータ)Keyboard shortcuts (keyboard accelerator)
    • アクセス キー (キーボード アクセラレータ)Access keys (keyboard accelerator)
    • マウスとペンのホバー ボタン (ポインター アクセラレータ)Mouse & Pen hover buttons (pointer accelerator)

注意

ユーザーは、どの種類のデバイスからでも、すべてのコマンドにアクセスできる必要があります。Users should be able to access all commands from any type of device. たとえば、アプリのコマンドがホバー ボタン ポインター アクセラレータでしか公開されない場合、タッチ ユーザーはコマンドにアクセスできません。For example, if your app’s commands are only exposed through hover button pointer accelerators, touch users won't be able to access them. 少なくとも、すべてのコマンドにアクセスできるコンテキスト メニューを使います。At a minimum, use a context menu to provide access to all commands.

例:PodcastObject データ モデルExample: The PodcastObject data model

推奨されるコマンド実行のデモとして、この記事では、ポッドキャスト アプリ用のポッドキャスト リストを作成します。To demonstrate our commanding recommendations, this article creates a list of podcasts for a podcast app. コード例では、ユーザーがリストから特定のポッドキャストを "お気に入り" に追加できるようにする方法を示しています。The example code demonstrate how to enable the user to "favorite" a particular podcast from a list.

以下に、この記事で作業するポッドキャスト オブジェクトの定義を示します。Here's the definition for the podcast object we'll be working with:

public class PodcastObject : INotifyPropertyChanged
{
    // The title of the podcast
    public String Title { get; set; }

    // The podcast's description
    public String Description { get; set; }

    // Describes if the user has set this podcast as a favorite
    public bool IsFavorite
    {
        get
        {
            return _isFavorite;
        }
        set
        {
            _isFavorite = value;
            OnPropertyChanged("IsFavorite");
        }
    }
    private bool _isFavorite = false;

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(String property)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
    }
}

PodcastObject は INotifyPropertyChanged を実装して、ユーザーが IsFavorite プロパティの設定を切り替えたときに、プロパティの変更に応答するようにしています。Notice that the PodcastObject implements INotifyPropertyChanged to respond to property changes when the user toggles the IsFavorite property.

ICommand インターフェイスを使ったコマンドの定義Defining commands with the ICommand interface

ICommand インターフェイス を使うと、複数の入力の種類に利用できるコマンドを定義できます。The ICommand interface helps you to define a command that's available for multiple input types. たとえば、Delete キーが押されたときと、コンテキスト メニューで [削除] が右クリックされたときの 2 種類のイベント ハンドラーで同じ削除コマンドのコードを記述するのではなく、ICommand として削除ロジックを 1 度実装したら、各種入力方法でこの削除ロジックを利用可能にできます。For example, instead of writing the same code for a delete command in two different event handlers, one for when the user presses the Delete key and one for when the user right clicks "Delete" in a context menu, you can implement your delete logic once, as an ICommand, and then make it available to different input types.

"お気に入り" の操作を表す ICommand を定義する必要があります。We need to define the ICommand that represents the "Favorite" action. ポッドキャストをお気に入りに追加するには、コマンドの Execute メソッドを使います。We will use the command's Execute method to favorite a podcast. 特定のポッドキャストがコマンドのパラメーターを介して実行メソッドに渡されます。これは、CommandParameter プロパティを使ってバインドできます。The particular podcast will be provided to the execute method via the command's parameter, which can be bound using the CommandParameter property.

public class FavoriteCommand: ICommand
{
    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return true;
    }
    public void Execute(object parameter)
    {
        // Perform the logic to "favorite" an item.
        (parameter as PodcastObject).IsFavorite = true;
    }
}

複数のコレクションや要素で同じコマンドを使うには、コマンドをページやアプリのリソースとして保存します。To use the same command with multiple collections and elements, you can store the command as a resource on the page or on the app.

<Application.Resources>
    <local:FavoriteCommand x:Key="favoriteCommand" />
</Application.Resources>

コマンドを実行するには、コマンドの Execute メソッドを呼び出します。To execute the command, you call its Execute method.

// Favorite the item using the defined command
var favoriteCommand = Application.Current.Resources["favoriteCommand"] as ICommand;
favoriteCommand.Execute(PodcastObject);

さまざまな入力に応答する UserControl の作成Creating a UserControl to respond to a variety of inputs

項目のリストがあり、各項目が複数の入力方法に応答する場合、項目の UserControl を定義し、これを使って項目のコンテキスト メニューとイベント ハンドラーを定義することで、コードを簡潔にできます。When you have a list of items and each of those items should respond to multiple inputs, you can simplify your code by defining a UserControl for the item and using it to define your items' context menu and event handlers.

Visual Studio で UserControl を作る手順は次のとおりです。To create a UserControl in Visual Studio:

  1. ソリューション エクスプローラーで、プロジェクトを右クリックします。In the Solution Explorer, right click the project. コンテキスト メニューが表示されます。A context menu appears.
  2. [追加]、[新しい項目] の順に選びます。Select Add > New Item...
    [新しい項目の追加] ダイアログが表示されます。The Add New Item dialog appears.
  3. 項目の一覧から [UserControl] を選択します。Select UserControl from the list of items. 任意の名前を付けて、 [追加] をクリックします。Give it the name you want and click Add. Visual Studio によって UserControl のスタブが生成されます。Visual Studio will generate a stub UserControl for you.

この記事のポッドキャストの例では、各ポッドキャストはリストにまとめられて表示され、さまざまな方法でポッドキャストを ”お気に入り” に追加できるようになります。In our podcast example, each podcast will be displayed in a list, which will expose a variety of ways to "Favorite" a podcast. ユーザーは次の操作によって、ポッドキャストを ”お気に入り” にすることができます。The user will be able to perform the following actions to "Favorite" the podcast:

  • コンテキスト メニューの呼び出しInvoke a context menu
  • キーボード ショートカットの実行Perform keyboard shortcuts
  • ホバー ボタンの表示Show a hover button
  • スワイプ ジェスチャの実行Perform a swipe gesture

これらの動作をカプセル化して、FavoriteCommand を使えるように、リスト内のポッドキャストを表す "PodcastUserControl" という名前の新しい UserControl を作りましょう。In order to encapsulate these behaviors and use the FavoriteCommand, let's create a new UserControl named "PodcastUserControl" to represent a podcast in the list.

PodcastUserControl は PodcastObject のフィールドを TextBlocks として表示し、さまざまなユーザーの操作に応答します。The PodcastUserControl displays the fields of the PodcastObject as TextBlocks, and responds to various user interactions. この記事では、この PodcastUserControl を参照し、拡張していきます。We will reference and expand upon the PodcastUserControl throughout this article.

PodcastUserControl.xamlPodcastUserControl.xaml

<UserControl
    x:Class="ContextCommanding.PodcastUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    IsTabStop="True" UseSystemFocusVisuals="True"
    >
    <Grid Margin="12,0,12,0">
        <StackPanel>
            <TextBlock Text="{x:Bind PodcastObject.Title, Mode=OneWay}" Style="{StaticResource TitleTextBlockStyle}" />
            <TextBlock Text="{x:Bind PodcastObject.Description, Mode=OneWay}" Style="{StaticResource SubtitleTextBlockStyle}" />
            <TextBlock Text="{x:Bind PodcastObject.IsFavorite, Mode=OneWay}" Style="{StaticResource SubtitleTextBlockStyle}"/>
        </StackPanel>
    </Grid>
</UserControl>

PodcastUserControl.xaml.csPodcastUserControl.xaml.cs

public sealed partial class PodcastUserControl : UserControl
{
    public static readonly DependencyProperty PodcastObjectProperty =
        DependencyProperty.Register(
            "PodcastObject",
            typeof(PodcastObject),
            typeof(PodcastUserControl),
            new PropertyMetadata(null));

    public PodcastObject PodcastObject
    {
        get { return (PodcastObject)GetValue(PodcastObjectProperty); }
        set { SetValue(PodcastObjectProperty, value); }
    }

    public PodcastUserControl()
    {
        this.InitializeComponent();

        // TODO: We will add event handlers here.
    }
}

この PodcastUserControl では、PodcastObject への参照を DependencyProperty として維持しています。Notice that the PodcastUserControl maintains a reference to the PodcastObject as a DependencyProperty. これで、PodcastObjects を PodcastUserControl にバインドできるようになります。This enables us to bind PodcastObjects to the PodcastUserControl.

いくつか PodcastObjects を生成したら、PodcastObjects を ListView にバインドして、ポッドキャストのリストを作成できます。After you have generated some PodcastObjects, you can create a list of podcasts by binding the PodcastObjects to a ListView. PodcastUserControl オブジェクトは、PodcastObjects の視覚エフェクトを記述します。したがって、ListView の ItemTemplate を使って設定します。The PodcastUserControl objects describe the visualization of the PodcastObjects, and are therefore set using the ListView's ItemTemplate.

MainPage.xamlMainPage.xaml

<ListView x:Name="ListOfPodcasts"
            ItemsSource="{x:Bind podcasts}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:PodcastObject">
            <local:PodcastUserControl PodcastObject="{x:Bind Mode=OneWay}" />
        </DataTemplate>
    </ListView.ItemTemplate>
    <ListView.ItemContainerStyle>
        <!-- The PodcastUserControl will entirely fill the ListView item and handle tabbing within itself. -->
        <Style TargetType="ListViewItem" BasedOn="{StaticResource ListViewItemRevealStyle}">
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            <Setter Property="Padding" Value="0"/>
            <Setter Property="IsTabStop" Value="False"/>
        </Style>
    </ListView.ItemContainerStyle>
</ListView>

コンテキスト メニューの作成Creating context menus

コンテキスト メニューは、ユーザーの要求に応じて、コマンドやオプションの一覧を表示します。Context menus display a list of commands or options when the user requests them. コンテキスト メニューは、アタッチされた要素に関連するコンテキスト コマンドを提供します。また、通常、その項目固有のセカンダリ操作のために予約されています。Context menus provide contextual commands related to their attached element, and are generally reserved for secondary actions specific to that item.

項目のコンテキスト メニューを表示する

ユーザーは、以下の "コンテキスト アクション" を使ってコンテキスト メニューを呼び出すことができます。The user can invoke context menus using these "context actions":

入力Input コンテキスト アクションContext action
マウスMouse 右クリックします。Right click
キーボードKeyboard Shift + F10、メニュー ボタンShift+F10, Menu button
TouchTouch 項目を長押しLong press on item
ペンPen バレル ボタンを押す、項目を長押しBarrel button press, long press on item
ゲームパッドGamepad メニュー ボタンMenu button

ユーザーはさまざまな種類の入力方法でコンテキスト メニューを開く可能性があるため、リストの項目に対して実行できるコンテキスト コマンドの全部をコンテキスト メニューに含めてください。Since the user can open a context menu regardless of input type, your context menu should contain all of the contextual commands available for the list item.

ContextFlyoutContextFlyout

UIElement クラスによって定義される ContextFlyout プロパティ を利用すると、すべての入力の種類で使えるコンテキスト メニューを簡単に作成できます。The ContextFlyout property, defined by the UIElement class, makes it easy to create a context menu that works with all input types. コンテキスト メニューを表すポップアップは MenuFlyout を使って提供します。上記で定義した “コンテキスト操作” をユーザーが実行すると、項目に対応する MenuFlyout が表示されます。You provide a flyout representing your context menu using MenuFlyout, and when the user performs a “context action” as defined above, the MenuFlyout corresponding to the item will be displayed.

ContextFlyout を PodcastUserControl に追加します。We will add a ContextFlyout to the PodcastUserControl. ContextFlyout として指定された MenuFlyout には、ポッドキャストをお気に入りに追加するための項目が 1 つだけ含まれています。The MenuFlyout specified as the ContextFlyout contains a single item to favorite a podcast. この MenuFlyoutItem では上記で定義した favoriteCommand を使い、CommandParamter が PodcastObject にバインドされていることに注意してください。Notice that this MenuFlyoutItem uses the favoriteCommand defined above, with the CommandParamter bound to the PodcastObject.

PodcastUserControl.xamlPodcastUserControl.xaml

<UserControl>
    <UserControl.ContextFlyout>
        <MenuFlyout>
            <MenuFlyoutItem Text="Favorite" Command="{StaticResource favoriteCommand}" CommandParameter="{x:Bind PodcastObject, Mode=OneWay}" />
        </MenuFlyout>
    </UserControl.ContextFlyout>
    <Grid Margin="12,0,12,0">
        <!-- ... -->
    </Grid>
</UserControl>

また、ContextRequested イベント を使って、コンテキスト操作に応答することもできます。Note that you can also use the ContextRequested event to respond to context actions. ContextRequested イベントは、ContextFlyout が指定されている場合は発生しません。The ContextRequested event will not fire if a ContextFlyout has been specified.

入力アクセラレータの作成Creating input accelerators

コレクション内の各項目のコンテキスト コマンドをすべて含むコンテキスト メニューを用意することをお勧めしますが、よく実行される特定のコマンドをユーザーがすばやく実行できるようにすることも一案です。Although each item in the collection should have a context menu containing all contextual commands, you might want to enable users to quickly perform a smaller set of frequently performed commands. たとえば、メール アプリであれば、応答、アーカイブ、フォルダーへ移動、フラグの設定、削除などのセカンダリ コマンドをコンテキスト メニューに表示しますが、最もよく使われるコマンドは削除とフラグの設定です。For example, a mailing app may have secondary commands like Reply, Archive, Move to Folder, Set Flag, and Delete which appear in a context menu, but the most common commands are Delete and Flag. 最もよく使われるコマンドを特定したら、入力ベースのアクセラレータを使って、これらのコマンドをユーザーが実行しやすくできます。After you have identified which commands are most common, you can use input-based accelerators to make these commands easier for a user to perform.

ポッドキャスト アプリでは、頻繁に実行されるコマンドは ”お気に入り” コマンドです。In the podcast app, the frequently performed command is the "Favorite" command.

キーボード アクセラレータKeyboard accelerators

ショートカットと直接キーの処理Shortcuts and direct key handling

Ctrl キーと F キーを押して操作を実行

コンテンツの種類に応じて、操作を実行する特定のキーの組み合わせを明らかにします。Depending on the type of content, you may identify certain key combinations that should perform an action. たとえば、メール アプリでは、選択されたメールの削除に Del キーが使われる可能性があります。In an email app, for example, the DEL key may be used to delete the email that is selected. ポッドキャスト アプリでは、Ctrl + S や F キーによって、後で視聴するためにポッドキャストをお気に入りに追加する可能性があります。In a podcast app, the Ctrl+S or F keys could favorite a podcast for later. Del キーで削除するなど、よく知られた一般的なキーボード ショートカットがあるコマンドもあれば、アプリまたはドメイン固有のショートカットがあるコマンドもあります。Although some commands have common, well-known keyboard shortcuts like DEL to delete, other commands have app- or domain-specific shortcuts. できればよく知られているショートカットを使用してください。または、ヒントでリマインダー テキストを表示してショートカット コマンドをユーザーに伝えることを検討してください。Use well-known shortcuts if possible, or consider providing reminder text in a tooltip to teach the user about the shortcut command.

KeyDown イベントを使うことで、アプリはユーザーがキーを押したときに応答できます。Your app can respond when the user presses a key using the KeyDown event. 通常ユーザーは、押したキーを放すときではなく、キーを最初に押したときにアプリが応答するものと考えます。In general, users expect that the app will respond when they first press the key down, rather than waiting until they release the key.

次の例では、KeyDown ハンドラーを PodcastUserControl に追加して、ユーザーが Ctrl + S または F キーを押したときにポッドキャストをお気に入りに追加する方法を示しています。このコードでは、前と同じコマンドを使っています。This example walks through how to add the KeyDown handler to the PodcastUserControl to favorite a podcast when the user presses Ctrl+S or F. It uses the same command as before.

PodcastUserControl.xaml.csPodcastUserControl.xaml.cs

// Respond to the F and Ctrl+S keys to favorite the focused item.
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
    var ctrlState = CoreWindow.GetForCurrentThread().GetKeyState(VirtualKey.Control);
    var isCtrlPressed = (ctrlState & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down || (ctrlState & CoreVirtualKeyStates.Locked) == CoreVirtualKeyStates.Locked;

    if (e.Key == Windows.System.VirtualKey.F || (e.Key == Windows.System.VirtualKey.S && isCtrlPressed))
    {
        // Favorite the item using the defined command
        var favoriteCommand = Application.Current.Resources["favoriteCommand"] as ICommand;
        favoriteCommand.Execute(PodcastObject);
    }
}

マウス アクセラレータMouse accelerators

項目の上にマウス ポインターを重ねてボタンを表示

右クリックのコンテキスト メニューはユーザーにとっておなじみですが、マウスのクリック 1 回で、よく使われるコマンドを実行できるようにしても便利です。Users are familiar with right-click context menus, but you may wish to empower users to perform common commands using only a single click of the mouse. このエクスペリエンスを実現するには、専用のボタンをコレクション項目のキャンバスに含めます。To enable this experience, you can include dedicated buttons on your collection item's canvas. ユーザーがマウスを使ってすばやく操作できるようにすると同時に、不要な表示をできる限りなくすには、特定のリスト項目内にポインターが置かれたときに、専用のボタンのみが表示されるようにすることができます。To both empower users to act quickly using mouse, and to minimize visual clutter, you can choose to only reveal these buttons when the user has their pointer within a particular list item.

次の例では、PodcastUserControl 内で直接定義したボタンによって、お気に入りコマンドを提示しています。In this example, the Favorite command is represented by a button defined directly in the PodcastUserControl. なお、この例のボタンでも、以前と同じ FavoriteCommand コマンドを使っています。Note that the button in this example uses the same command, FavoriteCommand, as before. このボタンの表示と非表示を切り替えるには、VisualStateManager を使って、ボタンの領域内にポインターが置かれたときと、領域からポインターが外れたときに、表示の状態を切り替えることができます。To toggle visibility of this button, you can use the VisualStateManager to switch between visual states when the pointer enters and exits the control.

PodcastUserControl.xamlPodcastUserControl.xaml

<UserControl>
    <UserControl.ContextFlyout>
        <!-- ... -->
    </UserControl.ContextFlyout>
    <Grid Margin="12,0,12,0">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="HoveringStates">
                <VisualState x:Name="HoverButtonsShown">
                    <VisualState.Setters>
                        <Setter Target="hoverArea.Visibility" Value="Visible" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="HoverButtonsHidden" />
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <StackPanel>
            <TextBlock Text="{x:Bind PodcastObject.Title, Mode=OneWay}" Style="{StaticResource TitleTextBlockStyle}" />
            <TextBlock Text="{x:Bind PodcastObject.Description, Mode=OneWay}" Style="{StaticResource SubtitleTextBlockStyle}" />
            <TextBlock Text="{x:Bind PodcastObject.IsFavorite, Mode=OneWay}" Style="{StaticResource SubtitleTextBlockStyle}"/>
        </StackPanel>
        <Grid Grid.Column="1" x:Name="hoverArea" Visibility="Collapsed" VerticalAlignment="Stretch">
            <AppBarButton Icon="OutlineStar" Label="Favorite" Command="{StaticResource favoriteCommand}" CommandParameter="{x:Bind PodcastObject, Mode=OneWay}" IsTabStop="False" VerticalAlignment="Stretch"  />
        </Grid>
    </Grid>
</UserControl>

ホバー ボタンは、マウス ポインターが項目に重なったら表示し、項目から外れたら非表示にします。The hover buttons should appear and disappear when the mouse enters and exits the item. マウス イベントに応答するには、PodcastUserControl で PointerEntered イベントと PointerExited イベントを使います。To respond to mouse events, you can use the PointerEntered and PointerExited events on the PodcastUserControl.

PodcastUserControl.xaml.csPodcastUserControl.xaml.cs

protected override void OnPointerEntered(PointerRoutedEventArgs e)
{
    base.OnPointerEntered(e);

    // Only show hover buttons when the user is using mouse or pen.
    if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse || e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Pen)
    {
        VisualStateManager.GoToState(this, "HoverButtonsShown", true);
    }
}

protected override void OnPointerExited(PointerRoutedEventArgs e)
{
    base.OnPointerExited(e);

    VisualStateManager.GoToState(this, "HoverButtonsHidden", true);
}

ホバー状態で表示されたボタンは、ポインター入力でしかアクセスできません。The buttons displayed in the hover state will only be accessible via the pointer input type. このボタンはポインター入力でしか操作できないため、ボタンのアイコンを囲む余白を最小限にするか完全になくして、ポインター入力向けに最適化することもできます。Because these buttons are limited to pointer input, you may choose to minimize or remove the padding around the icon of the button to optimize for pointer input. 余白をなくす場合は、ペンとマウスで操作できるように、ボタンのフットプリントを必ず 20 x 20 ピクセル以上にしてください。If you choose to do so, ensure that the button footprint is at least 20x20px to remain usable with pen and mouse.

タッチ アクセラレータTouch accelerators

SwipeSwipe

項目をスワイプしてコマンドを表示

スワイプによるコマンド実行は、タッチ デバイスを操作しているユーザーが、よく使われるセカンダリ操作をタッチを使って実行できるようにするタッチ アクセラレータです。Swipe commanding is a touch accelerator that enables users on touch devices to perform common secondary actions using touch. スワイプはタッチ ユーザーが、スワイプして削除やスワイプして呼び出すなどの一般的な操作を使って、コンテンツをすばやく自然に操作することを可能にします。Swipe empowers touch users to quickly and naturally interact with content, using common actions like Swipe-to-Delete or Swipe-to-Invoke. 詳しくは、スワイプによるコマンドの実行についての記事をご覧ください。See the swipe commanding article to learn more.

コレクションにスワイプを組み込むためには、2 つのコンポーネントが必要です: コマンドをホストする SwipeItems と、項目をラップしてスワイプにより操作できるようにする SwipeControl。In order to integrate swipe into your collection, you need two components: SwipeItems, which hosts the commands; and a SwipeControl, which wraps the item and allows for swipe interaction.

SwipeItems は、PodcastUserControl 内の Resource として定義できます。The SwipeItems can be defined as a Resource in the PodcastUserControl. 次の例では、SwipeItems に、項目をお気に入りに追加するコマンドが含まれています。In this example, SwipeItems contains a command to Favorite an item.

<UserControl.Resources>
    <SymbolIconSource x:Key="FavoriteIcon" Symbol="Favorite"/>
    <SwipeItems x:Key="RevealOtherCommands" Mode="Reveal">
        <SwipeItem IconSource="{StaticResource FavoriteIcon}" Text="Favorite" Background="Yellow" Invoked="SwipeItem_Invoked"/>
    </SwipeItems>
</UserControl.Resources>

SwipeControl は項目をラップし、ユーザーがスワイプ ジェスチャを使って項目を操作できるようにしています。The SwipeControl wraps the item and allows the user to interact with it using the swipe gesture. SwipeControl には、RightItems として SwipeItems への参照が含まれていることに注意してください。Notice that the SwipeControl contains a reference to the SwipeItems as its RightItems. ユーザーが右から左へスワイプすると、お気に入りの項目が表示されます。The Favorite item will show when the user swipes from right to left.

<SwipeControl x:Name="swipeContainer" RightItems="{StaticResource RevealOtherCommands}">
   <!-- The visual state groups moved from the Grid to the SwipeControl, since the SwipeControl wraps the Grid. -->
   <VisualStateManager.VisualStateGroups>
       <VisualStateGroup x:Name="HoveringStates">
           <VisualState x:Name="HoverButtonsShown">
               <VisualState.Setters>
                   <Setter Target="hoverArea.Visibility" Value="Visible" />
               </VisualState.Setters>
           </VisualState>
           <VisualState x:Name="HoverButtonsHidden" />
       </VisualStateGroup>
   </VisualStateManager.VisualStateGroups>
   <Grid Margin="12,0,12,0">
       <Grid.ColumnDefinitions>
           <ColumnDefinition Width="*" />
           <ColumnDefinition Width="Auto" />
       </Grid.ColumnDefinitions>
       <StackPanel>
           <TextBlock Text="{x:Bind PodcastObject.Title, Mode=OneWay}" Style="{StaticResource TitleTextBlockStyle}" />
           <TextBlock Text="{x:Bind PodcastObject.Description, Mode=OneWay}" Style="{StaticResource SubtitleTextBlockStyle}" />
           <TextBlock Text="{x:Bind PodcastObject.IsFavorite, Mode=OneWay}" Style="{StaticResource SubtitleTextBlockStyle}"/>
       </StackPanel>
       <Grid Grid.Column="1" x:Name="hoverArea" Visibility="Collapsed" VerticalAlignment="Stretch">
           <AppBarButton Icon="OutlineStar" Command="{StaticResource favoriteCommand}" CommandParameter="{x:Bind PodcastObject, Mode=OneWay}" IsTabStop="False" LabelPosition="Collapsed" VerticalAlignment="Stretch"  />
       </Grid>
   </Grid>
</SwipeControl>

ユーザーがスワイプしてお気に入りコマンドを呼び出すと、Invoked メソッドが呼び出されます。When the user swipes to invoke the Favorite command, the Invoked method is called.

private void SwipeItem_Invoked(SwipeItem sender, SwipeItemInvokedEventArgs args)
{
    // Favorite the item using the defined command
    var favoriteCommand = Application.Current.Resources["favoriteCommand"] as ICommand;
    favoriteCommand.Execute(PodcastObject);
}

引っ張って更新Pull to refresh

引っ張って更新を使うと、タッチ操作でデータのコレクションを引き下げることで、より多くのデータを取得できます。Pull to refresh lets a user pull down on a collection of data using touch in order to retrieve more data. 詳しくは、引っ張って更新についての記事をご覧ください。See the pull to refresh article to learn more.

ペン アクセラレータPen accelerators

ペン入力は、精度の高いポインター入力を実現します。The pen input type provides the precision of pointer input. ユーザーは、ペン ベースのアクセラレータを使って、コンテキスト メニューを開くなどの一般的な操作を実行できます。Users can perform common actions such as opening context menus using pen-based accelerators. コンテキスト メニューを開くには、バレル ボタンを押して画面をタップするか、コンテンツを長押しします。To open a context menu, users can tap the screen with the barrel button pressed, or long press on the content. また、マウスと同様に、ペンを使ってコンテンツにポインターを重ねて、ヒントを表示するなど、UI についての理解を深めたり、セカンダリのホバー操作を表示したりすることもできます。Users can also use the pen to hover over content to get a deeper understanding of the UI like displaying tooltips, or to reveal secondary hover actions, similar to mouse.

ペン入力用にアプリを最適化するには、ペン操作とスタイラス操作についての記事をご覧ください。To optimize your app for pen input, see the pen and stylus interaction article.

推奨と非推奨Do's and don'ts

  • どの種類の Windows デバイスでも、ユーザーがすべてのコマンドにアクセスできるようにします。Do make sure that users can access all commands from all types of Windows devices.
  • コレクション項目に対するコマンド全部にアクセスできるコンテキスト メニューを含めます。Do include a context menu that provides access to all the commands available for a collection item.
  • 頻繁に使われるコマンドについては、入力アクセラレータを提供します。Do provide input accelerators for frequently-used commands.
  • コマンドの実装には ICommand インターフェイス を使う。Do use the ICommand interface to implement commands.