入力の概要

Windows Presentation Foundation (WPF) サブシステムには、マウス、キーボード、タッチ、およびスタイラスを含むさまざまなデバイスから入力を取得するための強力な API が用意されています。ここでは、WPF によって提供されるサービスと、入力システムのアーキテクチャについて説明します。

このトピックは、次のセクションで構成されています。

  • 入力 API
  • イベントのルーティング
  • 入力イベントの処理
  • テキスト入力
  • タッチおよび操作
  • フォーカス
  • マウスの位置
  • マウス キャプチャ
  • コマンド
  • 入力システムと基本要素
  • 次の内容
  • 関連トピック

入力 API

公開されている主な入力 API は、基本要素クラス UIElementContentElementFrameworkElement、および FrameworkContentElement で提供されています。 基本要素の詳細については、「基本要素の概要」を参照してください。 これらのクラスは、キー操作、マウス ボタン、マウス ホイール、マウス動作、フォーカス管理、マウス キャプチャなどに関する入力イベントの機能を提供します。 入力アーキテクチャでは、すべての入力イベントをサービスとして処理するのではなく、基本要素に入力 API を配置することにより、UI 内の特定のオブジェクトによって入力イベントを供給し、複数の要素が入力イベントを処理できるイベント ルーティング方法をサポートしています。多くの入力イベントは、それぞれに関連付けられた一対のイベントがあります。 たとえば、キー押下イベントは、KeyDown イベントおよび PreviewKeyDown イベントと関連付けられています。 これらのイベントの違いは、ターゲット要素にルーティングされる方法です。 プレビュー イベントは、ルート要素からターゲット要素へ、要素ツリーを下位に向かいます (トンネル)。 バブル イベントは、ターゲット要素からルート要素へ、上位に向かいます (バブル)。 WPF のイベント ルーティングについては、この概要トピックの中、および「ルーティング イベントの概要」で詳細に説明します。

Keyboard クラスと Mouse クラス

基本要素クラスでの入力 API に加えて、Keyboard クラスと Mouse クラスでは、キーボード入力およびマウス入力を処理するための追加 API が提供されています。

Keyboard クラスでの入力 API の例としては、現在押されている ModifierKeys を返す Modifiers プロパティや、指定したキーが押されているかどうかを判断する IsKeyDown メソッドなどがあります。

次の例では、GetKeyStates メソッドを使用して、Key が押された状態であるかどうかを判断します。

            ' Uses the Keyboard.GetKeyStates to determine if a key is down.
            ' A bitwise AND operation is used in the comparison. 
            ' e is an instance of KeyEventArgs.
            If (Keyboard.GetKeyStates(Key.Return) And KeyStates.Down) > 0 Then
                btnNone.Background = Brushes.Red
// Uses the Keyboard.GetKeyStates to determine if a key is down.
// A bitwise AND operation is used in the comparison. 
// e is an instance of KeyEventArgs.
if ((Keyboard.GetKeyStates(Key.Return) & KeyStates.Down) > 0)
{
    btnNone.Background = Brushes.Red;
}

Mouse クラスの入力 API の例としては、マウスの中央ボタンの状態を取得する MiddleButton や、現在マウス ポインターの下にある要素を取得する DirectlyOver などがあります。

次の例では、マウスの LeftButtonPressed 状態であるかどうかを判断します。

            If Mouse.LeftButton = MouseButtonState.Pressed Then
                UpdateSampleResults("Left Button Pressed")
            End If
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
    UpdateSampleResults("Left Button Pressed");
}

Mouse クラスおよび Keyboard クラスについては、この概要でさらに詳しく説明します。

スタイラス入力

WPF では、Stylus が統合的にサポートされます。 Stylus は Tablet PC によって一般的になったペン入力です。 WPF アプリケーションでは、マウス API を使用してスタイラスをマウスとして処理できますが、WPF では、キーボードとマウスに類似したモデルを使用するスタイラス デバイス抽象クラスも公開されます。 スタイラス関連のすべての APIs には、"Stylus" という単語が含まれます。

スタイラスはマウスとして動作できるため、マウス入力だけをサポートするアプリケーションでも、ある程度のスタイラス入力が自動的にサポートされます。 スタイラスがこのように使用される場合、アプリケーションは、適切なスタイラス イベントを処理する機会が与えられた後、対応するマウス イベントを処理します。 さらに、インク入力などのより高いレベルのサービスも、スタイラス デバイス抽象クラスを介して使用できます。 入力としてのインクの詳細については、「インクの概要」を参照してください。

イベントのルーティング

FrameworkElement は、他の要素を子要素としてそのコンテンツ モデルに格納し、要素のツリーを形成できます。 WPF では、イベントを処理することによって、親要素が、その子要素またはその他の子孫要素に命令された入力に関与できます。 これは、小さいコントロールからコントロールを構築する場合に特に役立ちます。このプロセスは "コントロール コンポジション" または "合成処理" と呼ばれます。 要素ツリーおよび要素ツリーとイベント ルートの連携の詳細については、「WPF のツリー」を参照してください。

イベント ルーティングは、イベントを複数の要素に転送するプロセスであり、ルートに沿った特定のオブジェクトまたは要素が、異なる要素によって供給されたイベントに対して、(処理を介して) 重要な応答を提供できます。 ルーティング イベントには、直接、バブル、トンネルのいずれか 1 つのルーティング機構が使用されます。 直接ルーティングでは、ソース要素が通知を受ける唯一の要素であり、他の要素にイベントはルーティングされません。 ただし、標準の CLR イベントとは対照的に、直接ルーティング イベントは、ルーティング イベントにのみ存在するいくつかの追加機能を引き続き提供します。 バブル ルーティングでは、最初にイベントの発生元である要素に通知し、次にその親要素へと順に通知することで、要素ツリーの上位へ処理が実行されます。 トンネル ルーティングでは、要素ツリーのルートから始まり下位へと処理が実行され、ソース要素で処理が終了します。 ルーティング イベントの詳細については、「ルーティング イベントの概要」を参照してください。

一般に、WPF の入力イベントはトンネル イベントとバブル イベントが対になって構成されます。 トンネリング イベントは、"Preview" プレフィックスによってバブルリング イベントと区別されます。 たとえば、PreviewMouseMove はマウス移動イベントのトンネリング イベントであり、MouseMove は、このイベントのバブリング イベントです。 このイベントのペアは、要素レベルで実装される規則であり、WPF イベント システムの継承機能ではありません。 詳細については、「ルーティング イベントの概要」の「WPF の入力イベント」を参照してください。

入力イベントの処理

要素に対する入力を受け取るには、イベント ハンドラーをその特定のイベントに関連付ける必要があります。 XAML では、これは簡単です。イベントの名前を、このイベントをリッスンする要素の属性として参照します。 次に、属性の値を、デリゲートに基づいて、定義するイベント ハンドラーの名前に設定します。 イベント ハンドラーは、C# などのコードで記述する必要があり、分離コード ファイルに含めることができます。

キーボード イベントは、キーボード フォーカスが要素上にある状態で、オペレーティング システムがキー操作を報告すると発生します。 マウス イベントとスタイラス イベントにはそれぞれ、要素を基準とするポインター位置の変更を報告するイベントと、デバイス ボタンの状態の変更を報告するイベントの 2 種類があります。

キーボード入力イベントの例

左方向キーが押されるのを待ち受ける場合の例を次に示します。 Button を保持する StackPanel を作成します。 左方向キーが押されるのをリッスンするイベント ハンドラーを、Button インスタンスに結合します。

この例の最初の部分では、StackPanelButton を作成し、KeyDown のイベント ハンドラーを結合しています。

<StackPanel>
  <Button Background="AliceBlue"
          KeyDown="OnButtonKeyDown"
          Content="Button1"/>
</StackPanel>
            ' Create the UI elements.
            Dim keyboardStackPanel As New StackPanel()
            Dim keyboardButton1 As New Button()

            ' Set properties on Buttons.
            keyboardButton1.Background = Brushes.AliceBlue
            keyboardButton1.Content = "Button 1"

            ' Attach Buttons to StackPanel.
            keyboardStackPanel.Children.Add(keyboardButton1)

            ' Attach event handler.
            AddHandler keyboardButton1.KeyDown, AddressOf OnButtonKeyDown
// Create the UI elements.
StackPanel keyboardStackPanel = new StackPanel();
Button keyboardButton1 = new Button();

// Set properties on Buttons.
keyboardButton1.Background = Brushes.AliceBlue;
keyboardButton1.Content = "Button 1";

// Attach Buttons to StackPanel.
keyboardStackPanel.Children.Add(keyboardButton1);

// Attach event handler.
keyboardButton1.KeyDown += new KeyEventHandler(OnButtonKeyDown);

2 番目の部分はコード内に記述され、イベント ハンドラーを定義しています。 左方向キーが押され、Button にキーボード フォーカスがあると、ハンドラーが実行され、ButtonBackground の色が変更されます。 左方向キー以外のキーが押された場合は、ButtonBackground の色が開始時の色に変更されます。

        Private Sub OnButtonKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
            Dim source As Button = TryCast(e.Source, Button)
            If source IsNot Nothing Then
                If e.Key = Key.Left Then
                    source.Background = Brushes.LemonChiffon
                Else
                    source.Background = Brushes.AliceBlue
                End If
            End If
        End Sub
private void OnButtonKeyDown(object sender, KeyEventArgs e)
{
    Button source = e.Source as Button;
    if (source != null)
    {
        if (e.Key == Key.Left)
        {
            source.Background = Brushes.LemonChiffon;
        }
        else
        {
            source.Background = Brushes.AliceBlue;
        }
    }
}

マウス入力イベントの例

次の例では、マウス ポインターが Button に入ると、ButtonBackground の色を変更します。 マウスが Button から離れると、Background の色が元に戻ります。

この例の最初の部分では、StackPanelButton コントロールを作成し、MouseEnter イベントと MouseLeave イベントのイベント ハンドラーを Button に結合しています。

<StackPanel>
  <Button Background="AliceBlue"
          MouseEnter="OnMouseExampleMouseEnter"
          MouseLeave="OnMosueExampleMouseLeave">Button

  </Button>
</StackPanel>
            ' Create the UI elements.
            Dim mouseMoveStackPanel As New StackPanel()
            Dim mouseMoveButton As New Button()

            ' Set properties on Button.
            mouseMoveButton.Background = Brushes.AliceBlue
            mouseMoveButton.Content = "Button"

            ' Attach Buttons to StackPanel.
            mouseMoveStackPanel.Children.Add(mouseMoveButton)

            ' Attach event handler.
            AddHandler mouseMoveButton.MouseEnter, AddressOf OnMouseExampleMouseEnter
            AddHandler mouseMoveButton.MouseLeave, AddressOf OnMosueExampleMouseLeave
// Create the UI elements.
StackPanel mouseMoveStackPanel = new StackPanel();
Button mouseMoveButton = new Button();

// Set properties on Button.
mouseMoveButton.Background = Brushes.AliceBlue;
mouseMoveButton.Content = "Button";

// Attach Buttons to StackPanel.
mouseMoveStackPanel.Children.Add(mouseMoveButton);

// Attach event handler.
mouseMoveButton.MouseEnter += new MouseEventHandler(OnMouseExampleMouseEnter);
mouseMoveButton.MouseLeave += new MouseEventHandler(OnMosueExampleMouseLeave);

この例の 2 番目の部分はコード内に記述され、イベント ハンドラーを定義しています。 Button へのマウス入力があると、ButtonBackground の色が SlateGray に変更されます。 Button からマウスが離れると、ButtonBackground の色が AliceBlue に戻ります。

        Private Sub OnMouseExampleMouseEnter(ByVal sender As Object, ByVal e As MouseEventArgs)
            ' Cast the source of the event to a Button.
            Dim source As Button = TryCast(e.Source, Button)

            ' If source is a Button.
            If source IsNot Nothing Then
                source.Background = Brushes.SlateGray
            End If
        End Sub
private void OnMouseExampleMouseEnter(object sender, MouseEventArgs e)
{
    // Cast the source of the event to a Button.
    Button source = e.Source as Button;

    // If source is a Button.
    if (source != null)
    {
        source.Background = Brushes.SlateGray;
    }
}
        Private Sub OnMosueExampleMouseLeave(ByVal sender As Object, ByVal e As MouseEventArgs)
            ' Cast the source of the event to a Button.
            Dim source As Button = TryCast(e.Source, Button)

            ' If source is a Button.
            If source IsNot Nothing Then
                source.Background = Brushes.AliceBlue
            End If
        End Sub
private void OnMosueExampleMouseLeave(object sender, MouseEventArgs e)
{
    // Cast the source of the event to a Button.
    Button source = e.Source as Button;

    // If source is a Button.
    if (source != null)
    {
        source.Background = Brushes.AliceBlue;
    }
}

テキスト入力

TextInput イベントは、デバイスに依存しない方法でテキスト入力をリッスンできるようにします。 テキスト入力の主要な手段はキーボードですが、音声認識、手書き、およびその他の入力デバイスもテキスト入力を生成できます。

キーボード入力の場合、WPF は、最初に適切な KeyDown / KeyUp イベントを送信します。 そのイベントが処理されず、キーがテキストの場合 (方向キーやファンクション キーなどのコントロール キーでない場合)、TextInput イベントが発生します。 複数のキーストロークでテキスト入力の 1 文字が生成される場合や、単一のキーストロークで複数文字の文字列が生成される場合があるため、KeyDown/KeyUp、および TextInput の各イベント間の対応付けは、常に 1 対 1 の単純な対応付けであるとは限りません。 これは、Input Method Editors (IMEs) を使用して多くの異なる文字をそれぞれの対応するアルファベットで生成する、中国語、日本語、韓国語のような言語の場合に特に当てはまります。

WPF が KeyUp/KeyDown イベントを送信したときに、キーストロークが TextInput イベントの一部になる場合は (たとえば、Alt + S キーが押された場合)、KeyKey.System に設定されます。 これにより、KeyDown イベント ハンドラー内のコードが Key.System をチェックし、見つかった場合は、以降に発生する TextInput イベントのハンドラーの処理を任せます。 これらのケースでは、引数 TextCompositionEventArgs のさまざまなプロパティを使用して、元のキーストロークを決定できます。 同様に、IME が有効な場合、KeyKey.ImeProcessed の値を持ち、ImeProcessedKey により元のキーストロークが示されます。

次の例では、Click イベントのハンドラーと、KeyDown イベントのハンドラーを定義します。

コードまたはマークアップの最初の部分では、ユーザー インターフェイスを作成します。

<StackPanel KeyDown="OnTextInputKeyDown">
  <Button Click="OnTextInputButtonClick"
          Content="Open" />
  <TextBox> . . . </TextBox>
</StackPanel>
            ' Create the UI elements.
            Dim textInputStackPanel As New StackPanel()
            Dim textInputeButton As New Button()
            Dim textInputTextBox As New TextBox()
            textInputeButton.Content = "Open"

            ' Attach elements to StackPanel.
            textInputStackPanel.Children.Add(textInputeButton)
            textInputStackPanel.Children.Add(textInputTextBox)

            ' Attach event handlers.
            AddHandler textInputStackPanel.KeyDown, AddressOf OnTextInputKeyDown
            AddHandler textInputeButton.Click, AddressOf OnTextInputButtonClick
// Create the UI elements.
StackPanel textInputStackPanel = new StackPanel();
Button textInputeButton = new Button();
TextBox textInputTextBox = new TextBox();
textInputeButton.Content = "Open";

// Attach elements to StackPanel.
textInputStackPanel.Children.Add(textInputeButton);
textInputStackPanel.Children.Add(textInputTextBox);

// Attach event handlers.
textInputStackPanel.KeyDown += new KeyEventHandler(OnTextInputKeyDown);
textInputeButton.Click += new RoutedEventHandler(OnTextInputButtonClick);

コードの 2 つ目のセグメントには、イベント ハンドラーが含まれます。

        Private Sub OnTextInputKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
            If e.Key = Key.O AndAlso Keyboard.Modifiers = ModifierKeys.Control Then
                handle()
                e.Handled = True
            End If
        End Sub

        Private Sub OnTextInputButtonClick(ByVal sender As Object, ByVal e As RoutedEventArgs)
            handle()
            e.Handled = True
        End Sub

        Public Sub handle()
            MessageBox.Show("Pretend this opens a file")
        End Sub
private void OnTextInputKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.O && Keyboard.Modifiers == ModifierKeys.Control)
    {
        handle();
        e.Handled = true;
    }
}

private void OnTextInputButtonClick(object sender, RoutedEventArgs e)
{
    handle();
    e.Handled = true;
} 

public void handle()
{
    MessageBox.Show("Pretend this opens a file");
}

入力イベントはイベント ルートを上方向へ通知するので、どの要素にキーボード フォーカスがあっても StackPanel が入力を受け取ります。 TextBox コントロールが最初に通知され、TextBox が入力を処理しない場合のみ、OnTextInputKeyDown ハンドラーが呼び出されます。 KeyDown イベントの代わりに PreviewKeyDown イベントを使用すると、OnTextInputKeyDown ハンドラーが最初に呼び出されます。

この例では、Ctrl + O キー操作とボタンのクリック イベントの、2 回の処理ロジックが記述されています。 これは、入力イベントを直接処理するのではなく、コマンドを使用することで簡単化できます。 コマンドについては、この概要と「コマンド実行の概要」で詳しく説明します。

タッチおよび操作

Windows 7 オペレーティング システムの新しいハードウェアおよび API により、アプリケーションでは、複数のタッチからの入力を同時に受け取ることができます。 WPF を使用すると、アプリケーションでは、タッチが行われたときにイベントを発生させることにより、マウスやキーボードなどの他の入力に応答する場合と同様に、タッチを検出して応答できます。

WPF では、タッチが行われると、タッチ イベントと操作イベントという 2 種類のイベントを公開します。 タッチ イベントは、タッチスクリーン上の各指とその動きについて生データを提供します。 操作イベントは、入力を特定のアクションとして解釈します。 このセクションでは、この 2 種類のイベントについて説明します。

前提条件

タッチに応答するアプリケーションを開発するには、次のコンポーネントが必要です。

  • Microsoft Visual Studio 2010.

  • Windows 7。

  • Windows タッチをサポートするデバイス (タッチスクリーンなど)。

用語

タッチについて説明する際に使用する用語を次に示します。

  • タッチ: Windows 7 で認識されるユーザー入力の種類です。 通常、タッチを検知するスクリーンに指を当てると、タッチが開始されます。 ノート型コンピューターで一般的なタッチパッドなどのデバイスでは、デバイスによって指の位置と動きがマウス入力として変換されるだけの場合、タッチがサポートされないことに注意してください。

  • マルチタッチ: 複数のポイントから同時に行われるタッチです。 Windows 7 および WPF では、マルチタッチがサポートされています。 WPF に関するドキュメントでタッチについて説明されている場合、その概念はマルチタッチに当てはまります。

  • 操作: タッチが、オブジェクトに適用される物理的なアクションとして解釈されるときに発生します。 WPF では、操作イベントによって、平行移動、拡大と縮小、または回転の各操作として入力が解釈されます。

  • touch device: タッチスクリーンにおける 1 本の指など、タッチ入力を生成するデバイスを表します。

タッチに応答するコントロール

次のコントロールは、スクロールされて見えないコンテンツがある場合、コントロール上を指でドラッグするとスクロールできます。

ScrollViewer では、ScrollViewer.PanningMode 添付プロパティを定義します。このプロパティを使用すると、水平方向、垂直方向、またはその両方向のタッチ パンを有効にするか、あるいはタッチ パンを有効にしないかを指定できます。 ScrollViewer.PanningDeceleration プロパティでは、ユーザーがタッチスクリーンから指を離したときにスクロール速度を低下させる感度を指定します。 ScrollViewer.PanningRatio 添付プロパティでは、操作オフセットを平行移動するためにオフセットをスクロールする比率を指定します。

タッチ イベント

UIElementUIElement3D、および ContentElement の各基本クラスでは、アプリケーションがタッチに応答するようにサブスクライブできるイベントを定義します。 タッチ イベントは、アプリケーションでタッチがオブジェクトの操作以外の動作として解釈される場合に役立ちます。 たとえば、ユーザーが指を使って描画できるアプリケーションは、タッチ イベントにサブスクライブします。

この 3 つのクラスすべては、定義クラスに関係なく、動作がよく似た次のイベントを定義します。

タッチ イベントは、キーボード イベントやマウス イベントと同様に、ルーティング イベントです。 Preview で始まるイベントはトンネル イベントで、Touch で始まるイベントはバブル イベントです。 ルーティング イベントの詳細については、「ルーティング イベントの概要」を参照してください。 これらのイベントを処理するときは、GetTouchPoint メソッドまたは GetIntermediateTouchPoints メソッドを呼び出すことで、入力の位置を任意の要素に対する相対位置として取得できます。

タッチ イベント間の対話について理解するには、ユーザーがある要素の上に 1 本の指を置き、その要素内で指を動かした後、要素から指を離すシナリオを考えてみます。 次の図は、バブル イベントの実行について示しています (わかりやすくするため、トンネル イベントは省略しています)。

タッチ イベント

タッチ イベントの順序です。

次の一覧に、前の図のイベントのシーケンスを示します。

  1. ユーザーが要素の上に指を置くと、TouchEnter イベントが 1 回発生します。

  2. TouchDown イベントが 1 回発生します。

  3. ユーザーがその要素内で指を移動すると、それに従って TouchMove イベントが複数回発生します。

  4. ユーザーがその要素から指を離すと、TouchUp イベントが 1 回発生します。

  5. TouchLeave イベントが 1 回発生します。

3 本以上の指を使用した場合は、それぞれの指に対してイベントが発生します。

操作イベント

アプリケーションでユーザーがオブジェクトを操作できる場合、UIElement クラスは操作イベントを定義します。 単にタッチの位置を報告するタッチ イベントとは異なり、操作イベントは、入力をどのように解釈できるかを報告します。 操作には、平行移動、拡大と縮小、および回転の 3 種類があります。 3 種類の操作を呼び出す方法を次に示します。

  • 平行移動操作を呼び出すには、オブジェクトの上に指を置き、タッチスクリーン上で指を動かします。 通常、これによってオブジェクトが移動します。

  • 拡大と縮小操作を呼び出すには、オブジェクトの上に 2 本の指を置き、2 本の指を近づけたり離したりします。 通常、これによってオブジェクトのサイズが変更されます。

  • 回転操作を呼び出すには、オブジェクトの上に 2 本の指を置き、一方の指を中心にもう一方の指を回転させます。 通常、これによってオブジェクトが回転します。

2 種類以上の操作を同時に行うこともできます。

オブジェクトを操作に応答させると、オブジェクトに慣性があるように見せることができます。 これにより、オブジェクトに現実の世界をシミュレートさせることができます。 たとえば、テーブル上で 1 冊の書籍を押すときに、押す力が強すぎると、書籍は離した後も移動し続けます。 WPF を使用すると、ユーザーがオブジェクトから指を離した後に操作イベントを発生させることで、この動作をシミュレートできます。

ユーザーがオブジェクトの移動、サイズ変更、および回転を実行できるアプリケーションの作成方法については、「チュートリアル: 初めてのタッチ アプリケーションの作成」を参照してください。

UIElement では、次の操作イベントを定義します。

既定では、UIElement は、このような操作イベントを受け取りません。 UIElement で操作イベントを受け取るには、UIElement.IsManipulationEnabled を true に設定します。

操作イベントの実行パス

ユーザーがオブジェクトを "スローする" シナリオを考えてみます。 ユーザーはオブジェクトの上に指を置き、タッチスクリーン上で指を短い距離だけ移動し、オブジェクトの移動中に指を離します。 この結果、オブジェクトはユーザーの指の下で移動し、ユーザーが指を離した後も移動し続けます。

次の図は、操作イベントの実行パスと各イベントに関する重要な情報を示しています。

操作イベント

操作イベントの順序です。

次の一覧に、前の図のイベントのシーケンスを示します。

  1. ユーザーがオブジェクトの上に指を置くと、ManipulationStarting イベントが発生します。 特に、このイベントによって、ユーザーは ManipulationContainer プロパティを設定できるようになります。 後続のイベントでは、操作の位置は ManipulationContainer と相対的になります。 ManipulationStarting 以外のイベントでは、このプロパティは読み取り専用のため、ManipulationStarting イベントでのみ、このプロパティを設定できます。

  2. 次に、ManipulationStarted イベントが発生します。 このイベントは、操作の起点を報告します。

  3. ユーザーの指がタッチスクリーン上で移動すると、それに従って ManipulationDelta イベントが複数回発生します。 ManipulationDeltaEventArgs クラスの DeltaManipulation プロパティは、操作が移動、拡大と縮小、または平行移動のうちどの操作として解釈されるかを報告します。 ここで、オブジェクトを操作する作業の大半を実行します。

  4. ユーザーの指がオブジェクトから離れると、ManipulationInertiaStarting イベントが発生します。 このイベントにより、慣性による処理中の操作の減速を指定できます。 これは、必要に応じて、オブジェクトが異なる物理領域または属性をエミュレートできるためです。 たとえば、アプリケーションが現実の世界のアイテムを表す 2 つのオブジェクトを保持していて、一方のオブジェクトがもう一方のオブジェクトよりも重いとします。 重いオブジェクトを軽いオブジェクトよりもすばやく減速させることができます。

  5. 慣性による処理が発生すると、ManipulationDelta イベントが複数回発生します。 このイベントは、ユーザーの指がタッチスクリーン上で移動したときおよび WPF が慣性による処理をシミュレートしたときに発生します。 つまり、ManipulationDelta は、ManipulationInertiaStarting イベントの前後に発生します。ManipulationDeltaEventArgs.IsInertial プロパティは、慣性による処理中に ManipulationDelta イベントが発生するかどうかを報告します。そのため、そのプロパティをチェックし、その値に応じて異なるアクションを実行できます。

  6. 操作と慣性による処理が終了すると、ManipulationCompleted イベントが発生します。 つまり、すべての ManipulationDelta イベントが発生した後、ManipulationCompleted イベントが発生して、操作が完了したことを通知します。

UIElement では、ManipulationBoundaryFeedback イベントも定義します。 このイベントは、ReportBoundaryFeedback メソッドが ManipulationDelta イベント内で呼び出されると発生します。 ManipulationBoundaryFeedback イベントを使用すると、アプリケーションまたはコンポーネントでは、オブジェクトが境界に接したときに視覚的フィードバックを提供できるようになります。 たとえば、Window クラスでは、ManipulationBoundaryFeedback イベントを処理して、ウィンドウの端に当たったときにそのウィンドウを少し移動します。

操作を取り消すには、任意の操作イベント (ManipulationBoundaryFeedback イベントを除く) のイベント引数で Cancel メソッドを呼び出します。 Cancel を呼び出すと、操作イベントは発生しなくなり、タッチに対してマウス イベントが発生します。 次の表に、操作が取り消される時間と発生するマウス イベントとの間の関係を示します。

Cancel が呼び出されるイベント

既に行われている入力に対して発生するマウス イベント

ManipulationStarting および ManipulationStarted

マウス ダウン イベント。

ManipulationDelta

マウス ダウン イベントおよびマウス移動イベント。

ManipulationInertiaStarting および ManipulationCompleted

マウス ダウン イベント、マウス移動イベント、およびマウス アップ イベント。

慣性による処理中に操作が行われる場合に Cancel を呼び出したときは、メソッドによって false が返され、入力によってマウス イベントが発生しないことに注意してください。

タッチ イベントと操作イベントの関係

UIElement では、常にタッチ イベントを受け取ることができます。 IsManipulationEnabled プロパティを true に設定した場合、UIElement ではタッチ イベントと操作イベントの両方を受け取ることができます。 TouchDown イベントが処理されない場合 (つまり、Handled プロパティを false に設定した場合)、操作ロジックでは要素へのタッチをキャプチャし、操作イベントを生成します。 TouchDown イベントの Handled プロパティを true に設定した場合、操作ロジックでは操作イベントを生成しません。 次の図は、タッチ イベントと操作イベントの関係を示しています。

タッチ イベントと操作イベント

タッチ イベントと操作イベントのリレーションシップ

次の一覧に、前の図に示したタッチ イベントと操作イベントの関係を示します。

フォーカス

WPF では、フォーカスに関してキーボード フォーカスと論理フォーカスという 2 つの主要な概念があります。

キーボード フォーカス

キーボード フォーカスは、キーボード入力を受け取っている要素を指します。 キーボード フォーカスを持つ要素は、デスクトップ全体で 1 つしかありません。 WPF では、キーボード フォーカスを持つ要素の IsKeyboardFocused は true に設定されます。 Keyboard の静的メソッド FocusedElement は、現在キーボード フォーカスを持っている要素を返します。

キーボード フォーカスは、TextBox などの要素に Tab キーで移動したり、特定の要素でマウスをクリックしたりすることで取得できます。 キーボード フォーカスは、Keyboard クラスで Focus メソッドを使用してプログラムにより取得することもできます。 Focus は、指定された要素にキーボード フォーカスを設定しようとします。 Focus によって返される要素は、現在キーボード フォーカスを持っている要素です。

要素でキーボード フォーカスを取得するためには、Focusable プロパティと IsVisible プロパティを true に設定する必要があります。 Panel などの一部のクラスでは、Focusable の既定値は false です。したがって、要素がキーボード フォーカスを取得できるようにする場合は、このプロパティを true に設定する必要があります。

Focus を使用して、キーボード フォーカスを Button に設定する例を次に示します。 アプリケーションで初期フォーカスを設定する場所は、Loaded イベント ハンドラー内にすることをお勧めします。

        Private Sub OnLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Sets keyboard focus on the first Button in the sample.
            Keyboard.Focus(firstButton)
        End Sub
private void OnLoaded(object sender, RoutedEventArgs e)
{
    // Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton);
}

キーボード フォーカスの詳細については、「フォーカスの概要」を参照してください。

論理フォーカス

論理フォーカスとは、フォーカス範囲内の FocusManager.FocusedElement を意味します。 アプリケーションでは、複数の要素が論理フォーカスを持つことがありますが、特定のフォーカス範囲で論理フォーカスを持つ要素は 1 つだけに限られます。

フォーカス範囲とは、その範囲内の FocusedElement を追跡するコンテナー要素です。 フォーカスがフォーカス範囲を離れると、フォーカスがある要素はキーボード フォーカスを失いますが、論理フォーカスは引き続き保持します。 フォーカスがフォーカス範囲に戻ると、フォーカスがある要素はキーボード フォーカスを得ます。 これにより、キーボード フォーカスが複数のフォーカス範囲間で変更されても、フォーカスが戻ると、そのフォーカス範囲内のフォーカスのある要素が再びフォーカスのある要素になることが保証されます。

Extensible Application Markup Language (XAML) で FocusManager の添付プロパティ IsFocusScope を true に設定することで、またはコードで SetIsFocusScope メソッドを使用してこの添付プロパティを設定することで、要素をフォーカス範囲内に変更できます。

IsFocusScope 添付プロパティを設定して、StackPanel をフォーカス範囲にする例を次に示します。

<StackPanel Name="focusScope1" 
            FocusManager.IsFocusScope="True"
            Height="200" Width="200">
  <Button Name="button1" Height="50" Width="50"/>
  <Button Name="button2" Height="50" Width="50"/>
</StackPanel>
            Dim focuseScope2 As New StackPanel()
            FocusManager.SetIsFocusScope(focuseScope2, True)
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);

既定でフォーカス範囲になる、WPF のクラスは、WindowMenuToolBar、および ContextMenu です。

キーボード フォーカスを持つ要素は、その要素が属するフォーカス範囲の論理フォーカスも持ちます。したがって、Keyboard クラスまたは基本要素クラスの Focus メソッドで要素にフォーカスを設定することは、その要素へのキーボード フォーカスと論理フォーカスの設定を試みることになります。

フォーカス範囲内でフォーカスのある要素を判断するには、GetFocusedElement を使用します。 フォーカス範囲内でフォーカスのある要素を変更するには、SetFocusedElement を使用します。

論理フォーカスの詳細については、「フォーカスの概要」を参照してください。

マウスの位置

WPF の 入力 API は、座標空間に関する役立つ情報を提供します。 たとえば、座標 (0,0) は左上の座標ですが、これはツリーのどの要素の左上でしょうか。 入力対象の要素でしょうか。 イベント ハンドラーを結び付けた要素でしょうか。 または、それ以外でしょうか。 混乱を防ぐため、WPF の入力 API でマウスを介して取得した座標を扱う場合は、座標系を指定する必要があります。 GetPosition メソッドは、指定した要素を基準としたマウス ポインターの座標を返します。

マウス キャプチャ

マウス デバイスは、マウス キャプチャと呼ばれるモーダル特性を特別に備えています。 マウス キャプチャは、ドラッグ アンド ドロップ操作の開始時に、入力の遷移状態を保持する目的で使用されます。これにより、マウス ポインターの画面上での公称位置に関係する他の操作が、必ずしも発生しません。 ドラッグの間、ユーザーはドラッグ アンド ドロップを中止しない限りクリックできません。マウス キャプチャはドラッグ元によって保持されますが、マウスを置いたときの手掛かりの大部分は適切でなくなります。 入力システムは、マウス キャプチャの状態を判断できる APIs、および、特定の要素に対してマウス キャプチャを実行したり、マウス キャプチャの状態をクリアできる APIs を公開します。 ドラッグ アンド ドロップ操作の詳細については、「ドラッグ アンド ドロップの概要」を参照してください。

コマンド

コマンドでは、デバイス入力と比べて、より意味的なレベルで入力を処理できます。 コマンドは、Cut、Copy、Paste、Open などの簡単なディレクティブです。 コマンドは、コマンド ロジックを集中化する場合に役立ちます。 MenuToolBar、またはキーボード ショートカットから、同じコマンドにアクセスできます。 またコマンドは、コマンドが使用できない場合にコントロールを無効にするための機構を提供します。

RoutedCommand は、WPF での ICommand の実装です。 RoutedCommand を実行すると、コマンドの対象で PreviewExecuted イベントと Executed イベントが発生し、他の入力と同様に要素ツリー内をトンネリングおよびバブリングします。 コマンドの対象が設定されていない場合は、キーボード フォーカスを持つ要素がコマンドの対象になります。 コマンドを実行するロジックは、CommandBinding に結び付けられます。 Executed イベントがその特定のコマンドの CommandBinding に到達すると、CommandBindingExecutedRoutedEventHandler が呼び出されます。 このハンドラーが、コマンドのアクションを実行します。

コマンド実行の詳細については、「コマンド実行の概要」を参照してください。

WPF には、ApplicationCommandsMediaCommandsComponentCommandsNavigationCommands、および EditingCommands で構成される一般的なコマンドのライブラリが用意されています。または、独自のライブラリを定義することもできます。

TextBox にキーボード フォーカスがある場合に、MenuItem がクリックされると TextBoxPaste コマンドを呼び出すように MenuItem を設定する方法を次の例に示します。

<StackPanel>
  <Menu>
    <MenuItem Command="ApplicationCommands.Paste" />
  </Menu>
  <TextBox />
</StackPanel>
            ' Creating the UI objects
            Dim mainStackPanel As New StackPanel()
            Dim pasteTextBox As New TextBox()
            Dim stackPanelMenu As New Menu()
            Dim pasteMenuItem As New MenuItem()

            ' Adding objects to the panel and the menu
            stackPanelMenu.Items.Add(pasteMenuItem)
            mainStackPanel.Children.Add(stackPanelMenu)
            mainStackPanel.Children.Add(pasteTextBox)

            ' Setting the command to the Paste command
            pasteMenuItem.Command = ApplicationCommands.Paste
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();

// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);

// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;

// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;

WPF のコマンドの詳細については、「コマンド実行の概要」を参照してください。

入力システムと基本要素

MouseKeyboard、および Stylus クラスによって定義される添付イベントなどの入力イベントは、入力システムによって発生し、実行時に行われるビジュアル ツリーのヒット テストに基づいて、オブジェクト モデル内の特定の位置に挿入されます。

MouseKeyboard、および Stylus によって添付イベントとして定義される各イベントは、基本要素クラスの UIElement および ContentElement でも、新しいルーティング イベントとして再度公開されます。 基本要素のルーティング イベントは、元の添付イベントを処理し、イベント データを再利用するクラスによって生成されます。

入力イベントが、その基本要素の入力イベント実装を通じて特定のソース要素に関連付けられると、論理ツリー オブジェクトとビジュアル ツリー オブジェクトの組み合わせに基づく残りのイベント ルートを通じてルーティングされ、アプリケーション コードで処理されます。 一般に、XAML とコードの両方で直感的なイベント ハンドラー構文を使用できるため、UIElement および ContentElement のルーティング イベントを使用して、このようなデバイス関連の入力イベントを処理すると便利です。 プロセスを開始した添付イベントを処理することもできますが、いくつかの問題があります。添付イベントには、基本要素クラス処理によって処理されることがマークされる可能性があり、添付イベントに対してハンドラーを添付するために、本当のイベント構文ではなく、アクセサー メソッドを使用する必要があります。

次の内容

WPF で入力を処理するさまざまな方法について説明しました。 また、さまざまな種類の入力イベントと、WPF で使用されるルーティングされたイベントの機能について、理解を深める必要があります。

WPF のフレームワーク要素とイベントのルーティングの詳細を説明するリソースが他にもあります。 詳細については、「コマンド実行の概要」、「フォーカスの概要」、「基本要素の概要」、「WPF のツリー」、および「ルーティング イベントの概要」を参照してください。

参照

概念

フォーカスの概要

コマンド実行の概要

ルーティング イベントの概要

基本要素の概要

その他の技術情報

プロパティ