Windows Presentation Foundation (WPF)サブシステムは、マウス、キーボード、タッチとスタイラスが含まれる、いろいろなデバイスからの入力を取得するために、強力なAPIを提供します。このトピックでは、WPFが提供するサービスについて説明し、入力システムのアーキテクチャについて説明します。
入力API
Input API
主要な公開された入力APIは、基本的な要素クラスで見つかります。:
UIElement、ContentElement、FrameworkElementとFrameworkContentElement。基本的な要素の詳細については、「基底要素の概要」を参照してください。これらのクラスは、キーを押す、マウスボタン、マウスホイール、マウスの動き、フォーカス管理、およびマウスキャプチャに関係する入力イベントのための機能を提供します。入力APIを基本的な要素に配置することによって、すべての入力イベントをサービスとして扱うのではなく、入力アーキテクチャは、UIの特別なオブジェクトによって、そして、入力イベントを取り扱うための複数の要素に可能性があるイベント・ルーティング・スキームをサポートするために、入力イベントを供給することができます。多くの入力イベントは、それらに関連するイベントのペアを持っています。たとえば、key downイベントは、KeyDownとPreviewKeyDownイベントに関連付けられています。これらのイベントの違いは、ターゲット要素に送られる方法です。プレビュー・イベントは、ルート要素からターゲット要素まで、要素ツリーのトンネルを掘り下げます。バブリング・イベントは、ターゲット要素からルート要素までバブルアップします。WPFのイベントルーティングについては、この概要と「ルーティングイベントの概要」で詳しく説明します。
キーボードとマウス・クラス
Keyboard and Mouse Classes
基本的な要素クラスの入力APIに加えて、KeyboardクラスとMouseクラスは、キーボードとマウス入力で動作するための追加のAPIを提供します。
Keyboardクラスの入力APIの例は、現在、押されているModifierKeysを返すModifiersプロパティです。IsKeyDownメソッドは、指定されたキーが押されるかどうかを判断します。
以下の例では、Keyが押されている状態かどうかを判断するために、GetKeyStatesメソッドを使用します。
// Keyboard.GetKeyStatesを使用して、キーを押しているかどうかを判断します。
// 比較には、ビット単位のAND演算が使用されます。
// eは、KeyEventArgsのインスタンスです。
if ((Keyboard.GetKeyStates(Key.Return) & KeyStates.Down) > 0)
{
btnNone.Background = Brushes.Red;
}
Mouseクラスの入力APIの例は、中央のマウス・ボタンの状態とマウス・ポインタが、現在存在する要素を取得するDirectlyOverを取得するMiddleButtonです。
次の例では、マウスのLeftButtonがPressed状態かどうかを判断します。
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
UpdateSampleResults("Left Button Pressed");
}
MouseとKeyboardクラスは、この概要を通して更に詳細に説明します。
スタイラス入力
Stylus Input
WPFは、Stylusのためにサポートを統合しています。Stylusは、タブレットPCで人気のあるペン入力です。WPFアプリケーションは、マウスAPIを使用して、スタイラスをマウスとして扱うことができますが、WPFは、キーボードとマウスに似たモデルを使用する、スタイラス・デバイスの抽象化も公開しています。すべてのスタイラスに関連したAPIには、「Stylus」という単語が含まれています。
スタイラスは、マウスとして機能できるため、マウス入力だけをサポートするアプリケーションは、まだ、自動的に、いくつかのレベルのスタイラス・サポートを取得することができます。スタイラスが、そのような方法で使用されるとき、アプリケーションは、適切なスタイラス・イベントを取り扱う機会が与えられ、続いて、対応するマウス・イベントを取り扱います。加えて、インク入力のような、高レベルのサービスは、スタイラス・デバイスの抽象化からも利用できます。入力としてのインクの詳細については、「インク入門」を参照してください。
イベント・ルーティング
Event Routing
FrameworkElementは、要素のツリーを形成する、そのコンテンツ・モデルの子要素として、他の要素を含めることができます。WPFでは、親の要素は、イベントを伝えることで、その子要素や他の子孫を対象とした入力に関与することができます。これは、特に、「コントロールの構成」や「合成」として知られているプロセスの小さいコントロールからコントロールを構築する場合に便利です。要素ツリーと要素ツリーが、どのように、イベントの経路に関係があるかについての詳細は、「WPFのツリー」を参照してください。
イベント・ルーティングは、複数の要素にイベントを送り届けるプロセスです。そのため、経路に沿った特定のオブジェクトや要素は、異なる要素によって、供給されたかもしれないイベントへの重要な応答(処理を通して)を提供することを選択できます。Routedイベントは、次の3つのルーティング・メカニズムのいずれかを使用します。:直接、バブリングとトンネリング。直接のルーティングでは、ソース要素は、通知される唯一の要素です。そして、イベントは、他のどの要素にも送られません。しかしながら、直接ルーティング・イベントは、まだ、標準のCLRイベントではなく、ルーティング・イベントにのみ存在する、いくつかの追加機能を提供します。バブリングは、最初にイベントを供給した要素、続いて、親の要素などに通知することで、要素ツリー上を移動します。トンネリングは、要素ツリーのルートから始まり、下に向かって進み、元のソース要素で終了します。ルーティング・イベントの詳細については、「Routedイベントの概要」を参照してください。
WPF入力イベントは、通常、トンネリング・イベントとバブリング・イベントから構成されるペアで提供されます。トンネリング・イベントは、"Preview"接頭辞で、バブリング・イベントと区別されます。たとえば、PreviewMouseMoveは、マウス移動イベントのトンネリング・バージョンです。そして、MouseMoveは、このイベントのバブリング・バージョンです。このイベントの組合せは、要素レベルで実装される慣例であり、固有のWPFイベント・システムの機能では、ありません。詳細については、「Routedイベントの概要」でWPFの入力イベント・セクションを参照してください。
入力イベント処理
Handling Input Events
要素で入力を受け取るために、イベント・ハンドラは、その特定のイベントに関連付ける必要があります。XAMLでは、これは簡単です。:あなたは、このイベントに聞き耳をたてている、要素の属性として、イベントの名前を参照します。続いて、あなたは、デリゲートに基づいて、あなたが定義するために、イベント・ハンドラで、名前に属性の値を設定します。イベント・ハンドラは、C#のような、コードで記述する必要があります。そして、分離コード・ファイルに含めることができます。
オペレーティング・システムが、キーボードのフォーカスが、要素上にあるとき、発生する鍵となる動作を報告したとき、キーボード・イベントが、発生します。マウスとスタイラス・イベントは、それぞれ、2つのカテゴリーに分類されます。:要素と比較してポインタの位置の変化を報告するイベント、そして、デバイス・ボタンの状態の変化を報告するイベント。
キーボード入力イベントの例。
Keyboard Input Event Example
次の例では、左矢印キーが押されるのに聞き耳をたてます。Buttonを持つStackPanelが作成されます。左矢印キーが押されるのに聞き耳をたてるために、イベント・ハンドラは、Buttonインスタンスに添付されます。
例の最初のセクションは、StackPanelとButtonを作成して、KeyDownのためにイベント・ハンドラを添付します。
<StackPanel>
<Button Background="AliceBlue"
KeyDown="OnButtonKeyDown"
Content="Button1"/>
</StackPanel>
// UI要素を作成します。
StackPanel keyboardStackPanel = new StackPanel();
Button keyboardButton1 = new Button();
// Button上にプロパティを設定します。
keyboardButton1.Background = Brushes.AliceBlue;
keyboardButton1.Content = "Button 1";
// ButtonをStackPanelに添付します。
keyboardStackPanel.Children.Add(keyboardButton1);
// イベントハンドラを添付します。
keyboardButton1.KeyDown += new KeyEventHandler(OnButtonKeyDown);
2つ目のセクションは、コードで記述され、イベント・ハンドラを定義します。左矢印キーが押され、Buttonがキーボードのフォーカスを持っているとき、ハンドラが実行され、ButtonのBackground色が、変更されます。キーが押されたが、左矢印キーではない場合、ButtonのBackground色は、元の色に戻ります。
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に重なるとき、ButtonのBackground色が、変更されます。マウスが、Buttonから離れるとき、Background色が復元されます。
例の最初のセクションでは、StackPanelとButtonコントロールを作成します。そして、MouseEnterとMouseLeaveイベントのために、Buttonにイベント・ハンドラを添付します。
<StackPanel>
<Button Background="AliceBlue"
MouseEnter="OnMouseExampleMouseEnter"
MouseLeave="OnMosueExampleMouseLeave">Button
</Button>
</StackPanel>
// UI要素を作成します。
StackPanel mouseMoveStackPanel = new StackPanel();
Button mouseMoveButton = new Button();
// Button上にプロパティを設定します。
mouseMoveButton.Background = Brushes.AliceBlue;
mouseMoveButton.Content = "Button";
// ButtonをStackPanelに添付します。
mouseMoveStackPanel.Children.Add(mouseMoveButton);
// イベントハンドラを添付します。
mouseMoveButton.MouseEnter += new MouseEventHandler(OnMouseExampleMouseEnter);
mouseMoveButton.MouseLeave += new MouseEventHandler(OnMosueExampleMouseLeave);
例の2つ目のセクションでは、コードで記述され、イベント・ハンドラを定義します。マウスが、Buttonに重なるとき、ButtonのBackground色は、SlateGrayに変更されます。マウスが、Buttonから離れるとき、ButtonのBackground色は、AliceBlueに変更されます。
private void OnMouseExampleMouseEnter(object sender, MouseEventArgs e)
{
// Buttonにイベントのソースをキャストします。
Button source = e.Source as Button;
// ソースが、Buttonである場合。
if (source != null)
{
source.Background = Brushes.SlateGray;
}
}
private void OnMosueExampleMouseLeave(object sender, MouseEventArgs e)
{
// Buttonにイベントのソースをキャストします。
Button source = e.Source as Button;
// ソースが、Buttonである場合。
if (source != null)
{
source.Background = Brushes.AliceBlue;
}
}
テキスト入力
Text Input
TextInputイベントは、あなたが、デバイスに依存しない方法で、テキスト入力に聞き耳をたてることができます。キーボードは、テキスト入力の主要な手段ですが、音声、手書き、その他の入力デバイスは、テキスト入力も発生することができます。
キーボード入力のために、WPFは、まず、適切な、KeyDown/KeyUpイベントを送信します。それらのイベントが、処理されず、キーが、(Controlキーよりは、むしろ、矢印やファンクション・キーのような)テキストである場合、続いて、TextInputイベントが、発生します。複数のキーストロークが、テキスト入力の単一文字を生成できるため、KeyDown/KeyUpとTextInputイベントの間には、必ずしも単純な1対1のマッピングはありません。そして、単一のキーストロークは、複数文字の文字列を生成できます。これは、特に、入力方式エディター(IME)を使用して、対応するアルファベットで数千の文字を生成する、中国語、日本語、韓国語のような、言語に当てはまります。
WPFが、KeyUp/KeyDownイベントを送信するとき、Keyは、Key.Systemに設定されます。キーストロークが、TextInputイベントの一部になる可能性がある場合、(たとえば、ALT+Sが押された場合)。これは、コードが、KeyDownイベント・ハンドラで、Key.Systemを確認し、そして、見つかる場合、その後に発生するTextInputイベントのハンドラーの処理を終了します。これらの場合、TextCompositionEventArgs引数のさまざまなプロパティを使用して、元のキーストロークを決定できます。同様に、IMEが、アクティブである場合、Keyは、Key.ImeProcessedの値を持っています。そして、ImeProcessedKeyは、元のキーストロークやキーストロークを与えます。
次の例では、ClickイベントのハンドラーとKeyDownイベントのハンドラーを定義しています。
コードやマークアップの最初の部分は、ユーザー・インターフェイスを作成します。
<StackPanel KeyDown="OnTextInputKeyDown">
<Button Click="OnTextInputButtonClick"
Content="Open" />
<TextBox> . . . </TextBox>
</StackPanel>
// UI要素を作成します。
StackPanel textInputStackPanel = new StackPanel();
Button textInputeButton = new Button();
TextBox textInputTextBox = new TextBox();
textInputeButton.Content = "Open";
// 要素をStackPanelに添付します。
textInputStackPanel.Children.Add(textInputeButton);
textInputStackPanel.Children.Add(textInputTextBox);
// イベント・ハンドラを添付します。
textInputStackPanel.KeyDown += new KeyEventHandler(OnTextInputKeyDown);
textInputeButton.Click += new RoutedEventHandler(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("これが、ファイルを開くふりをします");
}
入力イベントは、イベント・ルートをバブルアップするため、StackPanelは、キーボードのフォーカスを持つ要素に関係なく、入力を受け取ります。TextBoxコントロールが、まず、通知されます。そして、OnTextInputKeyDownハンドラは、TextBoxが入力を処理しなかった場合にのみ呼び出されます。PreviewKeyDownイベントが、KeyDownイベントの代わりに使用される場合、OnTextInputKeyDownハンドラが、最初に呼び出されます。
これの例では、処理ロジックは、2回、書き込まれます。-CTRL+Oのために1回、そして、ボタンのクリック・イベントに対して、もう一度。これは、直接、入力イベントを処理する代わりに、コマンドを使用することで簡素化できます。コマンドについては、この概要と「コマンドの概要」で説明しています。
タッチと操作
Touch and Manipulation
Windows 7オペレーティング・システムの新しいハードウェアとAPIは、アプリケーションに同時に複数のタッチから入力を受け取る機能を提供します。タッチが発生したとき、イベントを発生することによって、WPFは、アプリケーションが、マウスやキーボードのような、他の入力に応答するのと似た方法で、タッチを検出し、応答できます。
タッチが発生するとき、WPFは、2種類のイベントを公開します。:タッチ・イベントと操作イベント。タッチ・イベントは、タッチスクリーン上のそれぞれの指とその動きに関する生データを提供します。操作イベントは、入力を特定のアクションとして解釈します。両方の種類のイベントは、このセクションで説明されます。
必要条件
Prerequisites
あなたは、タッチに反応するアプリケーションを開発するために、以下のコンポーネントを必要とします。
- Visual Studio 2010.
- Windows 7.
- Windows Touchをサポートするタッチスクリーンのようなデバイス
用語
タッチについて説明するとき、次の用語が使用されます。
- タッチは、Windows 7によって認識されるユーザー入力の一種です。通常、タッチは、タッチスクリーン上に、指を置くことによって開始されます。デバイスが、指の位置と動きをマウス入力として単に変換する場合、ラップトップ・コンピュータが、タッチをサポートしないのは、一般的であり、タッチパッドのような、デバイスに注意してください。
- マルチタッチは、同時に複数の位置で発生するタッチです。Windows 7とWPFは、マルチタッチをサポートしています。WPFの文書でタッチについて説明するたびに、概念は、マルチタッチに適用されます。
- 操作は、タッチが、オブジェクトに適用される、物理的な動作として解釈される場合、発生します。WPFでは、操作イベントは、入力を平行移動、展開、または回転操作として解釈します。
- タッチ・デバイスは、タッチスクリーン上の1本の指のような、タッチ入力を作り出す、デバイスを示します。
タッチに反応するコントロール
Controls that Respond to Touch
次のコントロールは、コントロール上で、スクロールして表示されるコンテンツがある場合、指でドラッグすることでスクロールできます。
- ComboBox
- ContextMenu
- DataGrid
- ListBox
- ListView
- MenuItem
- TextBox
- ToolBar
- TreeView
ScrollViewerは、あなたが、タッチのパンが、水平、垂直、両方有効、両方無効かどうかを指定できる、ScrollViewer.PanningMode添付プロパティを定義します。ユーザーが、タッチスクリーンから指を離したとき、ScrollViewer.PanningDecelerationプロパティは、スクロールが、どれくらい速く失速するかを指定します。ScrollViewer.PanningRatio添付プロパティは、オフセット操作を変換するスクロール・オフセットの比率を指定します。
タッチ・イベント
Touch Events
基底クラス、UIElement、UIElement3D、ContentElementは、あなたが、あなたのアプリケーションが、タッチに反応するために、購読できるイベントを定義します。タッチ・イベントは、あなたのアプリケーションが、タッチをオブジェクトの操作以外の何かとして解釈する場合、役に立ちます。たとえば、ユーザーが、1本以上の指で描画できるアプリケーションは、タッチ・イベントを購読します。
3つのクラスは全て、定義するクラスに関係なく、同じように動作する以下のイベントを定義します。
- TouchDown
- TouchMove
- TouchUp
- TouchEnter
- TouchLeave
- PreviewTouchDown
- PreviewTouchMove
- PreviewTouchUp
- GotTouchCapture
- LostTouchCapture
キーボードとマウス・イベントのように、タッチ・イベントは、ルーティング・イベントです。Previewで始めるイベントは、トンネリング・イベントで、Touchで始まるイベントは、バブリング・イベントです。ルーティング・イベントの詳細については、Routedイベントの概要を参照してください。あなたが、これらのイベントを処理するとき、GetTouchPointやGetIntermediateTouchPointsメソッドを呼び出すことで、あなたは、要素と相対的な入力の位置を取得できます。
タッチ・イベント間の相互作用を理解するために、ユーザーが、要素に1本の指を置き、要素内で指を動かすシナリオを考えます。続いて、要素から、指を持ち上げます。次の図は、バブリング・イベントの実行を示しています。(簡単にするため、トンネリング・イベントは省略されています)。
次のリストは、前の図のイベントの順序を説明します。
- ユーザーが、要素に指を置くと、TouchEnterイベントが1回発生します。
- TouchDownイベントは、1回発生します。
- ユーザーが、要素内で指を動かすと、TouchMoveイベントが複数回発生します。
- ユーザーが、要素から指を離したとき、TouchUpイベントが、1回発生します。
- TouchLeaveイベントは、1回発生します。
- 2本以上の指が使用されるとき、イベントは、それぞれの指で発生します。
操作イベント
Manipulation Events
ユーザーが、アプリケーションで、オブジェクトを操作できる場合、UIElementクラスは、操作イベントを定義します。単にタッチの位置を伝えるタッチ・イベントとは異なり、操作イベントは、入力をどのように判断するかを伝えます。操作には、移動、拡大、回転の3つの種類があります。次のリストは、操作の3つの種類を、どのように呼び出すかを説明します。
- オブジェクトに指を置き、指をタッチスクリーン上で動かして、移動操作を呼び出します。これは、通常、オブジェクトを移動します。
- オブジェクトに2本の指を置き、指を互いに近づけたり離したりして、拡大操作を呼び出します。これは、通常、オブジェクトの大きさを変更します。
- オブジェクトに2本の指を置き、指を互いの周りで回転させて、回転操作を呼び出します。これは、通常、オブジェクトを回転します。
複数の種類の操作が、同時に発生する場合があります。
あなたが、操作に、オブジェクトを反応させるとき、あなたは、オブジェクトに慣性があるように見せかけることができます。これは、あなたのオブジェクトに物理的な世界をシミュレートさせることができます。たとえば、あなたが、テーブル越しに、本を押すとき、あなたが、本を十分強く押す場合、あなたが、それを離した後も継続して動き続けます。WPFでは、ユーザーの指が、オブジェクトを離した後に、操作イベントを発生させることにより、この動作をシミュレートできます。
ユーザーが、オブジェクトを移動、サイズ変更、回転できるアプリケーションを、どのように作成するかに関する情報については、Walkthroughを参照してください。:あなたの最初のタッチ・アプリケーションを作成する。
UIElementは、次の操作イベントを定義します。
- ManipulationStarting
- ManipulationStarted
- ManipulationDelta
- ManipulationInertiaStarting
- ManipulationCompleted
- ManipulationBoundaryFeedback
デフォルトでは、UIElementは、これらの操作イベントを受け取りません。UIElement上で操作イベントを受け取るために、UIElement.IsManipulationEnabledを、trueに設定します。
操作イベントの実行パス
The Execution Path of Manipulation Events
ユーザーが、オブジェクトを「投げる」シナリオを考えます。ユーザーはオブジェクトに指を置き、タッチスクリーン上で、指を短い距離だけ移動します。続いて、移動中に、指を持ち上げます。この結果、オブジェクトは、ユーザーの指の下に移動します。そして、ユーザーが、指を離した後も動き続けます。
次の図は、操作イベントの実行パスとそれぞれのイベントに関する重要な情報を示しています。
操作イベント
次のリストは、前の図のイベントの順序を説明します。
- ManipulationStartingイベントは、ユーザーが、オブジェクトに指を置いたときに発生します。とりわけ、このイベントは、ManipulationContainerプロパティを設定することができます。その後のイベントでは、操作の位置は、ManipulationContainerに相対的です。ManipulationStarting以外のイベントでは、このプロパティは、読み込み専用です。そのため、ManipulationStartingイベントは、あなたが、このプロパティを設定することができる唯一の時間です。
- 次に、ManipulationStartedイベントが発生します。このイベントは、操作の開始点を知らせます。
- ManipulationDeltaイベントは、ユーザーの指がタッチスクリーン上を移動するとき、複数回発生します。ManipulationDeltaEventArgsクラスのDeltaManipulationのプロパティは、操作が、移動、拡大、変形と解釈されるかどうかを知らせます。これは、あなたが、オブジェクトを操作するほとんどの作業を実行する場所です。
- ユーザーの指が、オブジェクトとの接触を失ったとき、ManipulationInertiaStartingイベントが、発生します。このイベントにより、慣性の操作中の減速を指定できます。ここれは、選択した場合、オブジェクトが、異なる物理空間や属性をエミュレートできるようにするためです。たとえば、あなたのアプリケーションが、物理的な世界のアイテムを表す2つのオブジェクトを持っており、1つは、もう一方より重いと仮定します。あなたは、重いオブジェクトを、軽いオブジェクトよりも速く減速させることができます。
- ManipulationDeltaイベントは、慣性が発生すると複数回発生します。ユーザーの指が、タッチスクリーン上を移動するとき、そして、WPFが、慣性をシミュレートするとき、このイベントが、発生することに注意してください。言い換えると、ManipulationDeltaが、ManipulationInertiaStartingイベントの前後で、発生します。ManipulationDeltaEventArgs.IsInertialプロパティは、ManipulationDeltaイベントが、慣性中に発生するかどうかにかかわらず、知らせます。そのため、その値に依存して、そのプロパティを確認し、さまざまな動作を実行できます。
- 操作と慣性が終了したとき、ManipulationCompletedイベントが、発生します。つまり、すべてのManipulationDeltaイベントが発生した後、操作が、完了したことを通知するために、ManipulationCompletedイベントが、発生します。
UIElementは、ManipulationBoundaryFeedbackイベントを定義します。このイベントが、ReportBoundaryFeedbackメソッドが、ManipulationDeltaイベントで呼び出されるとき、発生します。ManipulationBoundaryFeedbackイベントは、アプリケーションを有効にします。あるいは、オブジェクトが、境界に到達したとき、視覚的なフィードバックを提供するコンポーネント。たとえば、Windowクラスは、その端が遭遇するとき、ウィンドウのわずかな移動を引き起こすために、ManipulationBoundaryFeedbackイベントを取り扱います。
ManipulationBoundaryFeedbackイベントを除くすべての操作イベントで、イベント引数で、Cancelメソッドを呼び出すことにより、操作をキャンセルできます。あなたが、Cancelを呼び出すとき、操作イベントは、もはや発生しません。そして、タッチのために、マウス・イベントが、発生します。次の表は、操作が、キャンセルされる、そして、マウス・イベントが、発生する時の間の関係を説明しています。
Cancelが、呼び出されるイベント | 既に発生した入力に対して発生するマウス・イベント |
---|---|
ManipulationStartingとManipulationStarted | マウス・ダウン・イベント。 |
ManipulationDelta | マウス・ダウンとマウス移動イベント。 |
ManipulationInertiaStartingとManipulationCompleted | マウス・ダウン、マウス移動、マウス・アップ・イベント。 |
あなたが、Cancelを呼び出す場合、操作が、inertiaであるとき、メソッドは、falseを返し、入力は、マウス・イベントを発生しないことに注意してください。
タッチと操作イベントの関係
The Relationship Between Touch and Manipulation Events
UIElementは、常に、タッチ・イベントを受けることができます。IsManipulationEnabledプロパティが、trueに設定されている場合、UIElementは、タッチと操作イベントの両方を受けることができます。TouchDownイベントが、取り扱われない場合、(つまり、Handledプロパティは、falseです)、操作ロジックは、要素へのタッチをキャプチャします。そして、操作イベントを発生させます。Handledプロパティが、TouchDownイベントでtrueに設定される場合、操作ロジックは、操作イベントを発生させません。次の図は、タッチ・イベントと操作イベントの関係を示します。
タッチと操作イベント
次のリストは、前の図で示されている、タッチと操作イベントの関係を説明しています。
- 最初のタッチ・デバイスが、UIElement上で、TouchDownイベントを発生させるとき、操作ロジックは、GotTouchCaptureイベントを発生させる、CaptureTouchメソッドを呼び出します。
- GotTouchCaptureが、発生するとき、操作ロジックは、ManipulationStartingイベントを発生させる、Manipulation.AddManipulatorメソッドを呼び出します。
- TouchMoveイベントが発生するとき、操作ロジックは、ManipulationInertiaStartingイベントの前に発生する、ManipulationDeltaイベントを発生させます。
- 要素の最後のタッチ・デバイスが、TouchUpイベントを発生するとき、操作ロジックは、ManipulationInertiaStartingイベントを発生させます。
フォーカス
Focus
WPFでは、フォーカスに関係する2つの主要な概念があります。:キーボード・フォーカスと論理フォーカス。
キーボード・フォーカス
Keyboard Focus
キーボード・フォーカスは、キーボード入力を受け取っている、要素を参照します。デスクトップ全体に存在できる要素は、キーボード・フォーカスを持っている1つだけです。WPFでは、キーボード・フォーカスを持つ要素のIsKeyboardFocusedは、trueに設定されます。現在キーボード・フォーカスを持つ、静的KeyboardメソッドのFocusedElementは、要素を返します。
TextBoxのような、要素へのタブによって、あるいは、特定の要素でマウスをクリックすることによって、キーボード・フォーカスを取得できます。KeyboardクラスのFocusメソッドを使用することで、キーボード・フォーカスは、プログラム的に取得することもできます。フォーカスは、指定された要素にキーボード・フォーカスを与えようとします。Focusによって返される要素は、現在キーボード・フォーカスを持っている要素です。
要素が、キーボード・フォーカスを取得するために、FocusableプロパティとIsVisibleプロパティは、trueに設定する必要があります。Panelのような、いくつかのクラスは、デフォルトで、Focusableが、falseに設定されています。;この理由から、あなたが、その要素が、フォーカスを取得できるようにする場合、あなたは、このプロパティをtrueに設定する必要がある場合があります。
次の例は、Focusを使用して、Buttonにキーボード・フォーカスを設定します。アプリケーションの最初のフォーカスを設定するための推薦する場所は、Loadedイベント・ハンドラです。
private void OnLoaded(object sender, RoutedEventArgs e)
{
// サンプルの最初のButtonに、キーボード・フォーカスを設定します。
Keyboard.Focus(firstButton);
}
キーボード・フォーカスの詳細については、フォーカスの概要を参照してください。
論理フォーカス
Logical Focus
論理フォーカスは、フォーカス範囲で、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>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);
デフォルトでフォーカス範囲であるWPFのクラスは、Window、Menu、ToolBar、ContextMenuです。
キーボード・フォーカスを持っている要素は、それが属するフォーカス範囲の論理フォーカスを持っています。;この理由から、Keyboardクラス上にFocusメソッドを持つ要素上のフォーカスを設定します。あるいは、基底要素クラスは、要素に、キーボード・フォーカスと論理フォーカスを与えようとします。
フォーカス範囲でフォーカスした要素を決定するために、GetFocusedElementを使用します。フォーカス範囲のフォーカスした要素を変更するために、SetFocusedElementを使用します。
論理フォーカスの詳細については、フォーカスの概要を参照してください。
マウスの位置
Mouse Position
WPFの入力APIは、座標空間に関する有用な情報を提供します。たとえば、座標(0,0)は、左上の座標ですが、ツリーのどの要素の左上?入力ターゲットである要素?あなたが、イベント・ハンドラを接続した要素?あるいは、何か他のもの?混乱を避けるために、WPFの入力APIは、あなたが、マウスから取得した座標で作業するとき、参照フレームを指定することを要求します。GetPositionメソッドは、指定された要素にマウス・ポインタの相対的な座標を返します。
マウス・キャプチャ
Mouse Capture
マウス・デバイスは、特にマウス・キャプチャとして知られているモーダル特性を収集します。ドラッグ&ドロップ操作が開始されるとき、マウス・キャプチャは、過渡的な入力状態を維持するために使用されます。そのため、マウス・ポインタの名目上の画面上の位置が含まれる他の操作は、必ずしも発生しません。ドラッグしている間、ユーザーは、マウス・キャプチャが、ドラッグ元によって収集されている間、ほとんどのマウスオーバー・キューが不適切になり、ドラッグ&ドロップを中止しないで、クリックすることができません。入力システムは、特定の要素に、マウス・キャプチャを強制することができるAPIだけでなく、マウス・キャプチャの状態を判断できるAPIを公開する、あるいは、マウス・キャプチャの状態をクリアします。ドラッグ&ドロップ操作の詳細については、ドラッグ&ドロップの概要を参照してください。
コマンド
Commands
コマンドは、デバイス入力より意味レベルで、入力処理ができます。コマンドは、Cut、Copy、Paste、Openのような、単純な命令です。コマンドは、あなたのコマンド・ロジックを集中するために役に立ちます。同じコマンドは、Menuから、ToolBar上やキーボード・ショートカットを通じて、アクセスされる場合があります。コマンドは、コマンドが、利用できなくなったとき、コントロールを無効にするための仕組みも提供しています。
RoutedCommandは、ICommandのWPFの実装です。RoutedCommandが、実行されるとき、PreviewExecutedとExecutedイベントが、他の入力のような要素ツリーを通して、トンネルとバブルのコマンド・ターゲットで発生します。コマンド・ターゲットが、設定されていない場合、キーボード・フォーカスを持つ要素は、コマンド・ターゲットです。コマンドを実行するロジックは、CommandBindingに添付されます。Executedイベントが、その特定のコマンドのCommandBindingに到達すると、CommandBinding上のExecutedRoutedEventHandlerが、呼び出されます。このハンドラは、コマンドの動作を実行します。
コマンドの詳細については、「コマンドの概要」を参照してください。
ApplicationCommands、MediaCommands、ComponentCommands、NavigationCommandsとEditingCommandsから、構成されている、WPFの一般的なコマンドのライブラリを提供します。あるいは、あなたは、独自に定義できます。
次の例は、MenuItemを、どのように設定するかを示しています。そのため、リックされるとき、それは、TextBoxに、キーボード・フォーカスがあると仮定する、TextBox上で、Pasteコマンドを呼び出します。
<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste" />
</Menu>
<TextBox />
</StackPanel>
// UIオブジェクトを作成する
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();
// パネルとメニューにオブジェクトを追加します。
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);
// Pasteコマンドにコマンドを設定する
pasteMenuItem.Command = ApplicationCommands.Paste;
// コマンド・ターゲットをTextBoxに設定する
pasteMenuItem.CommandTarget = pasteTextBox;
WPFのコマンドの詳細については、「コマンドの概要」を参照してください。
入力システムと基底要素
The Input System and Base Elements
Mouse、Keyboard、Stylusクラスによって定義された添付イベントのような、入力イベントが、入力システムによって発生します。そして、実行時に、ビジュアル・ツリーのヒット・テストに基づいて、オブジェクト・モデルの特定の位置に挿入されます。
新しいルーティング・イベントとして、基底要素クラスUIElementとContentElementで、添付イベントとして定義される、それぞれのMouse、Keyboard、Stylusイベントは、再公開されます。元の添付イベントを処理するクラスによって、基底要素ルーティング・イベントが、作られます。そして、イベント・データを再利用します。
入力イベントが、その基底要素の入力イベントの実装を通じて、特定のソース要素に関連付けられるとき、それは、イベント・ルートの残りを経由してルーティングできます。これは、ロジカルとビジュアル・ツリー・オブジェクトの組み合わせに基づいており、そして、アプリケーション・コードによって処理されます。通常、UIElementとContentElementのルーティング・イベントを使用して、これらのデバイスに関連した入力イベントを取り扱うために、より便利です。なぜなら、あなたは、XAMLとコードで、より直観的なイベント・ハンドラ構文を使用することができます。あなたは、代わりにプロセスを開始する、添付イベントを処理することを選択できますが、あなたは、いくつかの問題に直面するでしょう:添付イベントは、基底要素クラス処理によって、処理済みと記録される場合があります。そして、あなたは、接続されたイベントのハンドラーを添付するには、trueイベント構文ではなく、アクセサ・メソッドを使用する必要があります。
次は
What's Next
あなたは、現在、WPFの入力を取り扱うための、いくつかの技術を持っています。あなたには、さまざまな種類の入力イベントとWPFが使用するルーティング・イベント・メカニズムについても理解を深める必要があります。
WPFのフレームワーク要素とイベント・ルーティングについて詳しく説明する追加のリソースが、利用できます。詳細については、以降の概要「コマンドの概要」、「フォーカスの概要」、「基底要素の概要」、「WPFのツリー」、「Routedイベントの概要」を参照してください。