次の方法で共有


入力の概要

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

入力 API

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

キーボードクラスとマウスクラス

基本要素クラスの入力 API に加えて、 Keyboard クラスと Mouse クラスには、キーボードとマウスの入力を操作するための追加の API が用意されています。

Keyboard クラスの入力 API の例としては、現在押されているModifiersを返す ModifierKeys プロパティと、指定したキーが押されているかどうかを決定する 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) & KeyStates.Down) > 0)
{
    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) And KeyStates.Down) > 0 Then
    btnNone.Background = Brushes.Red

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

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

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

MouseクラスとKeyboard クラスについては、この概要全体で詳しく説明します。

スタイラス入力

WPF には、 Stylusのサポートが統合されています。 Stylusは、タブレット PC で人気のあるペン入力です。 WPF アプリケーションでは、マウス API を使用してスタイラスをマウスとして扱うことができますが、WPF では、キーボードやマウスに似たモデルを使用するスタイラス デバイスの抽象化も公開されます。 スタイラス関連のすべての API には、"Stylus" という単語が含まれています。

スタイラスはマウスとして機能できるため、マウス入力のみをサポートするアプリケーションでは、何らかのレベルのスタイラスサポートを自動的に取得できます。 スタイラスをこのような方法で使用すると、アプリケーションには適切なスタイラス イベントを処理し、対応するマウス イベントを処理する機会が与えられます。 さらに、スタイラス デバイスの抽象化を通じて、インク入力などの上位レベルのサービスも利用できます。 入力としてのインクの詳細については、「インクの 概要」を参照してください。

イベント ルーティング

FrameworkElementは、コンテンツ モデルの子要素として他の要素を含め、要素のツリーを形成できます。 WPF では、親要素は、イベントを渡すことによって、子要素またはその他の子孫に送信される入力に参加できます。 これは、より小さなコントロール ("コントロールコンポジション" または "合成" と呼ばれるプロセス) からコントロールを構築する場合に特に便利です。要素ツリーと要素ツリーとイベント ルートの関係の詳細については、「 WPF のツリー」を参照してください。

イベント ルーティングは、複数の要素にイベントを転送するプロセスです。そのため、ルート上の特定のオブジェクトまたは要素は、別の要素によってソース化された可能性のあるイベントに対して (処理を通じて) 重要な応答を提供することを選択できます。 ルーティング イベントでは、ダイレクト、バブル、トンネリングの 3 つのルーティング メカニズムのいずれかを使用します。 直接ルーティングでは、ソース要素が通知される唯一の要素であり、イベントは他の要素にルーティングされません。 ただし、ダイレクト ルーティング イベントでは、標準の CLR イベントとは対照的に、ルーティング イベントにのみ存在するいくつかの追加機能が引き続き提供されます。 バブルは、最初にイベントをソースにした要素、次に親要素などを通知することで、要素ツリーを処理します。 トンネリングは要素ツリーのルートから開始され、下に向かって進み、元のソース要素で終わります。 ルーティング イベントの詳細については、「 ルーティング イベントの概要」を参照してください。

WPF 入力イベントは、通常、トンネリング イベントとバブル イベントで構成されるペアで構成されます。 トンネリング イベントは、"プレビュー" プレフィックスを持つバブル イベントと区別されます。 たとえば、 PreviewMouseMove はマウス移動イベントのトンネリング バージョンであり、 MouseMove はこのイベントのバブル バージョンです。 このイベント ペアリングは、要素レベルで実装される規則であり、WPF イベント システム固有の機能ではありません。 詳細については、「ルーティング イベントの概要」の「WPF 入力 イベント」セクションを参照してください。

入力イベントの処理

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

キーボード イベントは、キーボード フォーカスが要素にあるときに発生する主要なアクションをオペレーティング システムが報告するときに発生します。 マウス イベントとスタイラス イベントはそれぞれ、要素に対するポインター位置の変化を報告するイベントと、デバイス ボタンの状態の変化を報告するイベントという 2 つのカテゴリに分類されます。

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

次の例では、左方向キーの押下を検知します。 StackPanelを持つButtonが作成されます。 左方向キーの押下をリッスンするイベント ハンドラーが、 Button インスタンスにアタッチされます。

この例の最初のセクションでは、 StackPanelButton を作成し、 KeyDownのイベント ハンドラーをアタッチします。

<StackPanel>
  <Button Background="AliceBlue"
          KeyDown="OnButtonKeyDown"
          Content="Button1"/>
</StackPanel>
// 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);
' 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

2 番目のセクションはコードで記述され、イベント ハンドラーを定義します。 左方向キーが押され、Buttonにキーボード フォーカスがある場合、ハンドラーが実行され、BackgroundButtonの色が変更されます。 キーを押しても左方向キーではない場合は、BackgroundButtonの色が開始色に戻ります。

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;
        }
    }
}
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

マウス入力イベントの例

次の例では、マウス ポインターがBackgroundに入ると、ButtonButtonの色が変更されます。 マウスがBackgroundを離れると、Buttonの色が復元されます。

この例の最初のセクションでは、 StackPanelButton コントロールを作成し、 MouseEnter および MouseLeave イベントのイベント ハンドラーを Buttonにアタッチします。

<StackPanel>
  <Button Background="AliceBlue"
          MouseEnter="OnMouseExampleMouseEnter"
          MouseLeave="OnMosueExampleMouseLeave">Button
          
  </Button>
</StackPanel>
// 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);
' 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

この例の 2 番目のセクションはコードで記述され、イベント ハンドラーを定義します。 マウスがButtonに入ると、BackgroundButtonの色がSlateGrayに変更されます。 マウスがButtonを離れると、BackgroundButtonの色がAliceBlueに戻ります。

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 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 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;
    }
}
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

テキスト入力

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

キーボード入力の場合、WPF は最初に適切な KeyDown/KeyUp イベントを送信します。 これらのイベントが処理されず、キーが (方向矢印やファンクション キーなどのコントロール キーではなく) テキストである場合は、 TextInput イベントが発生します。 複数のキーストロークでテキスト入力の 1 文字を生成でき、1 回のキーストロークで複数の文字列を生成できるため、 KeyDown/KeyUp イベントと TextInput イベントの間に単純な 1 対 1 のマッピングが常に存在するとは限りません。 これは特に、入力メソッド エディター (IME) を使用して対応するアルファベットで数千の文字を生成する中国語、日本語、韓国語などの言語に当てはまります。

WPF がKeyUp/KeyDown イベントを送信すると、キーストロークがKey イベントの一部になる可能性がある場合 (Alt + S キーを押した場合など) にKey.SystemTextInputに設定されます。 これにより、 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.
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);
' 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

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

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");
}
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

入力イベントはイベント ルートをバブル アップするため、 StackPanel はキーボード フォーカスを持つ要素に関係なく、入力を受け取ります。 TextBox コントロールが最初に通知され、OnTextInputKeyDown ハンドラーは、TextBoxが入力を処理しなかった場合にのみ呼び出されます。 PreviewKeyDown イベントの代わりにKeyDown イベントが使用されている場合は、最初にOnTextInputKeyDown ハンドラーが呼び出されます。

この例では、処理ロジックが 2 回書き込まれます。1 回は Ctrl + O、もう 1 回はボタンのクリック イベントです。 これは、入力イベントを直接処理するのではなく、コマンドを使用して簡略化できます。 コマンドについては、この概要と コマンドの概要で説明します。

タッチと操作

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

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

[前提条件]

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

  • Visual Studio 2010。

  • Windows 7。

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

用語

タッチについて説明する場合は、次の用語が使用されます。

  • タッチ は、Windows 7 で認識されるユーザー入力の一種です。 通常、タッチはタッチに敏感な画面に指を置くことで開始されます。 ノート PC で一般的なタッチパッドなどのデバイスは、指の位置と動きをマウス入力として変換するだけではタッチをサポートしないことに注意してください。

  • マルチタッチ は、複数のポイントから同時に発生するタッチです。 Windows 7 と WPF では、マルチタッチがサポートされています。 WPF のドキュメントでタッチが説明されるたびに、概念はマルチタッチに適用されます。

  • 操作は、タッチがオブジェクトに適用される物理的なアクションとして解釈されるときに発生します。 WPF では、操作イベントは入力を翻訳、拡張、または回転操作として解釈します。

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

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

次のコントロールは、ビュー外にスクロールされたコンテンツがある場合に、コントロール全体に指をドラッグすることでスクロールできます。

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

タッチ イベント

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

3 つのクラスはすべて、定義クラスに関係なく、同様に動作する次のイベントを定義します。

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

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

タッチ イベントのシーケンス。 タッチ イベント

次の一覧では、前の図のイベントのシーケンスについて説明します。

  1. TouchEnter イベントは、ユーザーが要素に指を置いたときに 1 回発生します。

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

  3. TouchMove イベントは、ユーザーが要素内で指を動かすと複数回発生します。

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

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

2 本以上の指を使用すると、指ごとにイベントが発生します。

操作イベント

アプリケーションでユーザーがオブジェクトを操作できる場合、 UIElement クラスは操作イベントを定義します。 タッチの位置を報告するタッチ イベントとは異なり、操作イベントは入力の解釈方法を報告します。 操作には、平行移動、展開、回転の 3 種類があります。 次の一覧では、3 種類の操作を呼び出す方法について説明します。

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

  • オブジェクトに 2 本の指を置き、指を互いに近づけたり離したりして、拡張操作を呼び出します。 これは通常、オブジェクトのサイズを変更します。

  • オブジェクトに 2 本の指を置き、指を互いに回転させて回転操作を呼び出します。 これは通常、オブジェクトを回転させます。

複数の種類の操作を同時に実行できます。

オブジェクトが操作に応答する場合は、オブジェクトに慣性を持っているように見えることができます。 これにより、オブジェクトが物理世界をシミュレートできるようになります。 たとえば、書籍をテーブル全体にプッシュする場合、十分に強く押すと、書籍はリリース後も引き続き移動します。 WPF を使用すると、ユーザーの指がオブジェクトを離した後に操作イベントを発生させることで、この動作をシミュレートできます。

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

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

既定では、 UIElement はこれらの操作イベントを受け取りません。 UIElementで操作イベントを受信するには、UIElement.IsManipulationEnabledtrue に設定します。

操作イベントの実行パス

ユーザーがオブジェクトを投げるシナリオを考えてみましょう。 ユーザーはオブジェクトに指を置き、タッチスクリーン全体で指を短い距離移動してから、指を動かしながら持ち上げます。 その結果、オブジェクトはユーザーの指の下に移動し、ユーザーが指を離した後も引き続き移動します。

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

操作イベントのシーケンス。 操作イベント

次の一覧では、前の図のイベントのシーケンスについて説明します。

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

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

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

  4. ManipulationInertiaStarting イベントは、ユーザーの指がオブジェクトとの接触を失ったときに発生します。 このイベントを使用すると、慣性時の操作の減速を指定できます。 これは、選択した場合にオブジェクトが異なる物理スペースまたは属性をエミュレートできるようにするためです。 たとえば、アプリケーションに物理世界の項目を表す 2 つのオブジェクトがあり、一方が他方よりも重いとします。 重いオブジェクトは、軽いオブジェクトよりも速く減速させることができます。

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

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

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

操作のキャンセルは、Cancel イベントを除く任意の操作イベントで、イベント引数に対して ManipulationBoundaryFeedback メソッドを呼び出して行うことができます。 Cancelを呼び出すと、操作イベントが発生しなくなり、タッチ時にマウス イベントが発生します。 次の表では、操作が取り消された時刻と発生するマウス イベントの関係について説明します。

Cancel が呼び出されるイベント 既に発生した入力に対して発生するマウス イベント
ManipulationStartingManipulationStarted マウス ダウン イベント。
ManipulationDelta マウスダウンイベントとマウス移動イベント。
ManipulationInertiaStartingManipulationCompleted マウスダウン、マウス移動、マウスアップの各イベント。

操作が慣性のときに Cancel を呼び出すと、メソッドは false を返し、入力ではマウス イベントは発生しないことに注意してください。

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

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

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

次の一覧では、前の図に示したタッチ イベントと操作イベントの関係について説明します。

焦点

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

キーボード フォーカス

キーボード フォーカスは、キーボード入力を受け取る要素を指します。 キーボード フォーカスを持つ要素は、デスクトップ全体に 1 つだけ存在できます。 WPF では、キーボード フォーカスを持つ要素 IsKeyboardFocusedtrueに設定されます。 静的 Keyboard メソッド FocusedElement 現在キーボード フォーカスがある要素を返します。

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

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

次の例では、 Focus を使用して、 Buttonにキーボード フォーカスを設定します。 アプリケーションで初期フォーカスを設定する推奨される場所は、 Loaded イベント ハンドラーにあります。

private void OnLoaded(object sender, RoutedEventArgs e)
{
    // Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton);
}
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

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

論理フォーカス

論理フォーカスとは、フォーカス スコープ内の FocusManager.FocusedElement を指します。 アプリケーションには論理フォーカスを持つ複数の要素を含めることができますが、特定のフォーカス スコープに論理フォーカスを持つ要素は 1 つだけ存在する可能性があります。

フォーカス スコープは、スコープ内の FocusedElement を追跡するコンテナー要素です。 フォーカスがフォーカススコープから離れると、フォーカスされた要素はキーボードフォーカスを失いますが、論理フォーカスは保持されます。 フォーカスがフォーカス スコープに戻ると、フォーカスされた要素はキーボード フォーカスを取得します。 これにより、キーボードフォーカスを複数のフォーカススコープ間で変更できますが、フォーカスが戻ったときにフォーカススコープ内のフォーカスされた要素がフォーカスされた要素のままであることを保証します。

要素は、 FocusManager 添付プロパティの IsFocusScopetrueに設定するか、 SetIsFocusScope メソッドを使用して添付プロパティを設定してコード内で、拡張アプリケーション マークアップ言語 (XAML) のフォーカス スコープに変換できます。

次の例では、StackPanel 添付プロパティを設定して、IsFocusScope をフォーカス スコープにします。

<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>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);
Dim focuseScope2 As New StackPanel()
FocusManager.SetIsFocusScope(focuseScope2, True)

既定でフォーカス スコープである WPF のクラスは、WindowMenuToolBar、および ContextMenuです。

キーボード フォーカスを持つ要素には、それが属するフォーカス スコープの論理フォーカスもあります。したがって、Focus クラスまたは基本要素クラスの Keyboard メソッドを使用して要素にフォーカスを設定すると、要素にキーボード フォーカスと論理フォーカスを与えようとします。

フォーカス スコープ内のフォーカスされた要素を特定するには、 GetFocusedElementを使用します。 フォーカス スコープのフォーカスされた要素を変更するには、 SetFocusedElementを使用します。

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

マウスの位置

WPF 入力 API は、座標空間に関して役立つ情報を提供します。 たとえば、座標 (0,0) は左上の座標ですが、ツリー内のどの要素の左上ですか? 入力ターゲットである要素。 イベントハンドラーをアタッチした要素は? または他の何か? 混乱を避けるために、WPF 入力 API では、マウスで取得した座標を操作するときに参照フレームを指定する必要があります。 GetPosition メソッドは、指定した要素を基準としたマウス ポインターの座標を返します。

マウス キャプチャ

マウス デバイスは、特にマウス キャプチャと呼ばれるモーダル特性を保持します。 マウス キャプチャは、ドラッグ アンド ドロップ操作が開始されたときに遷移入力状態を維持するために使用されます。そのため、マウス ポインターの画面上のわずかな位置に関係する他の操作は必ずしも発生しません。 ドラッグ中、ユーザーはドラッグ アンド ドロップを中止せずにクリックすることはできません。これにより、マウスのキャプチャがドラッグ元によって保持されている間、ほとんどのマウスオーバー キューが不適切になります。 入力システムは、マウス キャプチャの状態を判断できる API と、特定の要素にマウス キャプチャを強制できる API、またはマウス キャプチャ状態をクリアする API を公開します。 ドラッグ アンド ドロップ操作の詳細については、「ドラッグ アンド ドロップの 概要」を参照してください。

コマンド

コマンドを使用すると、デバイス入力よりもセマンティック レベルで入力処理が有効になります。 コマンドは、 CutCopyPasteOpenなどの単純なディレクティブです。 コマンドは、コマンド ロジックを一元化するのに役立ちます。 同じコマンドは、 MenuToolBar、またはキーボード ショートカットからアクセスできます。 コマンドは、コマンドが使用できなくなったときにコントロールを無効にするメカニズムも提供します。

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

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

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

次の例は、MenuItemにキーボード フォーカスがあると仮定して、PasteをクリックしたときにTextBoxTextBox コマンドを呼び出すように設定する方法を示しています。

<StackPanel>
  <Menu>
    <MenuItem Command="ApplicationCommands.Paste" />
  </Menu>
  <TextBox />
</StackPanel>
// 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;
' 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

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

入力システムと基本要素

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

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

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

次の予定

WPF で入力を処理するいくつかの手法が用意されました。 また、さまざまな種類の入力イベントと、WPF で使用されるルーティング イベント メカニズムについても理解を深める必要があります。

WPF フレームワーク要素とイベント ルーティングについて詳しく説明する追加のリソースを使用できます。 詳細については、次の概要を参照してください。 コマンドの概要フォーカスの概要基本要素の概要WPF のツリー、ルーティング イベントの概要です。

こちらも参照ください