輸入概觀

Windows Presentation Foundation (WPF) 子系統提供強大的 API,可從各種裝置取得輸入,包括滑鼠、鍵盤、觸控和手寫筆。 本主題描述 WPF 所提供的服務,並說明輸入系統的架構。

輸入 API

主要輸入 API 暴露在基底元素類別 UIElement 上:、 ContentElementFrameworkElementFrameworkContentElement 。 如需基底項目的詳細資訊,請參閱基底項目概觀。 這些類別提供按鍵動作、滑鼠按鈕、滑鼠滾輪、滑鼠移動、焦點管理和滑鼠捕捉等相關輸入事件的功能。 藉由將輸入 API 放在基底元素上,而不是將所有輸入事件視為服務,輸入架構可讓輸入事件由 UI 中的特定物件進行來源,並支援事件路由配置,其中多個元素有機會處理輸入事件。 許多輸入事件都有一組與其建立關聯的事件。 例如,key down 事件與 KeyDownPreviewKeyDown 事件相關聯。 這些事件的差異在於如何將它們路由傳送至目標項目。 預覽事件會從根項目到目標項目往下瀏覽通道項目樹狀結構。 事件反昇事件會從目標項目往上反昇到根項目。 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 取得滑鼠指標目前已結束的專案。

下列範例會判斷滑鼠上的 是否 LeftButton 處於 Pressed 狀態。

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

MouseKeyboard 類別會在此概觀中更詳細地涵蓋。

手寫筆輸入

WPF 已整合對 Stylus 的支援。 Stylus是平板電腦熱門的手寫筆輸入。 WPF 應用程式可以使用滑鼠 API 將手寫筆視為滑鼠,但 WPF 也會公開手寫筆裝置抽象概念,其使用類似于鍵盤和滑鼠的模型。 所有手寫筆相關的 API 都包含 「Stylus」 一詞。

因為手寫筆可以當作滑鼠,所以只支援滑鼠輸入的應用程式仍然可以自動取得某種程度的手寫筆支援。 以這種方式使用手寫筆時,應用程式可以處理適當的手寫筆事件,然後處理對應的滑鼠事件。 此外,還可以透過手寫筆裝置抽象概念來取得筆跡輸入這類較高階服務。 如需將筆跡作為輸入的詳細資訊,請參閱筆跡入門

事件路由

FrameworkElement可以包含其他專案做為其 con帳篷模式l 中的子專案,形成專案的樹狀結構。 在 WPF 中,父元素可以藉由交出事件,參與導向至其子項目或其他子系的輸入。 這特別適用于從較小的控制項建置控制項、稱為「控制群組合」或「撰寫」的程式。如需專案樹狀結構的詳細資訊,以及專案樹狀架構與事件路由的關聯方式,請參閱 WPF 中的樹狀結構。

事件路由是將事件轉遞至多個項目的程序,因此,沿著路由的特定物件或項目可以選擇將重大回應提供給不同項目可能設為來源的事件 (透過處理)。 路由事件使用三種路由機制中的其中一種︰直接、事件反昇和通道。 在直接路由中,來源項目是唯一收到通知的項目,而且不會將事件路由傳送至任何其他項目。 不過,直接路由事件仍然提供一些額外的功能,這些功能僅適用于路由事件,而不是標準 CLR 事件。 事件反昇處理項目樹狀結構的方式是先通知將事件設為來源的項目,接著通知父項目,依此類推。 通道會從項目樹狀結構的根項目開始,然後往下進行,並結束於原始來源項目。 如需路由事件的詳細資訊,請參閱路由事件概觀

WPF 輸入事件通常會成對,其中包含通道事件和反升事件。 通道事件與事件反昇事件的區別在於 "Preview" 前置詞。 例如, PreviewMouseMove 是滑鼠移動事件的通道版本,而且 MouseMove 是這個事件的升起版本。 這個事件配對是在專案層級實作的慣例,不是 WPF 事件系統的固有功能。 如需詳細資訊,請參閱路由事件概觀中的<WPF 輸入事件>一節。

處理輸入事件

若要接收項目的輸入,事件處理常式必須與該特定事件建立關聯。 在 XAML 中,這很簡單:您會將事件的名稱參考為將接聽此事件之元素的屬性。 然後,您可以根據委派,將屬性的值設定為您所定義之事件處理常式的名稱。 事件處理常式必須以 C# 之類的程式碼撰寫,而且可以包含在程式碼後置檔案中。

作業系統報告在鍵盤焦點位於項目時所發生的按鍵動作時,會發生鍵盤事件。 滑鼠和手寫筆事件各分為兩個分類︰報告相對於項目之指標位置變更的事件,以及報告裝置按鈕狀態變更的事件。

鍵盤輸入事件範例

下列範例會接聽按下向左鍵作業。 StackPanel會建立具有 Button 的 。 接聽向左鍵按下的事件處理常式會附加至 Button 實例。

範例的第一個區段會 StackPanel 建立 和 Button ,並附加 的 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

第二個區段是使用程式碼所撰寫,並定義事件處理常式。 按下向左鍵且 Button 具有鍵盤焦點時,處理常式會執行 ,並 Background 變更 的 Button 色彩。 如果按下按鍵,但不是向左鍵,則 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 會變更 的色彩 ButtonButtonBackground 滑鼠離開 Button 時,會還原色彩。

範例的第一個區段會 StackPanel 建立 和 控制項, Button 並將 和 MouseLeave 事件的事件處理常式 MouseEnter 附加至 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

此範例的第二個區段是使用程式碼所撰寫,並定義事件處理常式。 當滑鼠進入 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 引發事件。 和 TextInput 事件之間 KeyUpKeyDown/ 不一定有簡單的一對一對應,因為多個擊鍵可以產生文字輸入的單一字元,而單一按鍵可能會產生多字元字串。 對於使用輸入法編輯器(IME)的中文、日文和韓文等語言來說,這尤其如此。

當 WPF 傳送 KeyUp/KeyDown 事件時,如果擊鍵可能成為事件的一 TextInput 部分, Key 則會設定為 Key.System (例如按下 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>
// 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

程式碼的第二個區段包含事件處理常式。

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 先呼叫 處理常式。

在此範例中,處理邏輯會撰寫兩次:一次針對 CTRL+O,一次則是針對按鈕的 Click 事件。 這可以使用命令進行簡化,而不是直接處理輸入事件。 這個概觀和命令概觀討論命令。

觸控和操作

Windows 7 作業系統中的新硬體和 API 讓應用程式可以同時接收來自多個觸控的輸入。 WPF 可讓應用程式偵測並回應觸控的方式,類似于回應其他輸入,例如滑鼠或鍵盤,方法是在觸控發生時引發事件。

WPF 會在觸控發生時公開兩種類型的事件:觸控事件和操作事件。 觸控事件提供觸控式螢幕上每根手指的未經處理資料和其移動。 操作事件會將輸入解譯成特定動作。 本節討論這兩種類型的事件。

必要條件

您需要下列元件,才能開發回應觸控的應用程式。

  • Visual Studio 2010。

  • Windows 7。

  • 支援 Windows Touch 的觸控式螢幕這類裝置。

辭彙

討論觸控時,會使用下列詞彙。

  • 觸控是 Windows 7 可辨識的一種使用者輸入類型。 通常,將手指放在觸控式螢幕上,就會起始觸控。 請注意,如果裝置只會將手指的位置和移動轉換為滑鼠輸入,則膝上型電腦上常見的觸控板這類裝置不支援觸控。

  • 多點觸控是同時從多點發生的觸控。 Windows 7 和 WPF 支援 multitouch。 每當 WPF 檔中討論觸控時,概念就會套用至 multitouch。

  • 將觸控解譯為套用至物件的實體動作時,會發生操作。 在 WPF 中,操作事件會將輸入解譯為轉譯、展開或旋轉操作。

  • touch device 所代表的裝置會產生觸控式螢幕上的一根手指這類觸控輸入。

回應觸控的控制項

如果控制項具有可捲動到檢視外部的內容,則將手指拖曳過該控制項即可捲動下列控制項。

ScrollViewerScrollViewer.PanningMode 定義附加屬性,讓您指定是否水準、垂直、兩者或兩者都啟用觸控移動流覽。 屬性 ScrollViewer.PanningDeceleration 會指定當使用者從觸控式螢幕上抬起手指時,捲動的速度會變慢。 ScrollViewer.PanningRatio附加屬性會指定捲動位移的比例,以平移操作位移。

觸控事件

基類 、 UIElementUIElement3DContentElement 會定義您可以訂閱的事件,讓應用程式回應觸控。 您的應用程式將觸控解譯為非操作物件的動作時,觸控事件十分有用。 例如,可讓使用者使用一或多根手指繪製的應用程式訂閱觸控事件。

不論定義類別為何,所有這三個類別都會定義下列行為類似的事件。

與鍵盤和滑鼠事件類似,觸控事件都是路由事件。 開頭為 Preview 的事件是通道事件,而開頭為 Touch 的事件是事件反昇事件。 如需路由事件的詳細資訊,請參閱路由事件概觀。 當您處理這些事件時,您可以藉由呼叫 GetTouchPointGetIntermediateTouchPoints 方法,取得輸入相對於任何專案的位置。

若要了解觸控事件之間的互動,請考慮在使用者將一根手指放在項目上,並將手指移至項目中,然後將手指移開項目。 下圖顯示事件反昇事件的執行 (為求簡化,會省略通道事件)。

The sequence of touch events. 觸控事件

下列清單描述上圖中的事件順序。

  1. 當使用者 TouchEnter 將手指放在 元素上時,就會發生一次此事件。

  2. 事件發生 TouchDown 一次。

  3. 當使用者移動元素內的手指時,就會 TouchMove 多次發生此事件。

  4. 當使用者 TouchUp 從 專案上抬起手指時,就會發生一次此事件。

  5. 事件發生 TouchLeave 一次。

使用兩根以上的手指時,每根手指都會發生這些事件。

操作事件

針對應用程式可讓使用者操作物件的情況,類別 UIElement 會定義操作事件。 與只會報告觸控位置的觸控事件不同,操作事件會報告輸入解譯方式。 操作有三種類型:平移、擴充和旋轉。 下列清單描述如何叫用這三種類型的操作。

  • 將手指放在物件上,然後將手指移過觸控式螢幕,以叫用轉譯操作。 這通常會移動物件。

  • 將兩根手指放在物件上,然後拉近兩根手指或分開兩根手指,以叫用擴充操作。 這通常會調整物件大小。

  • 將兩根手指放在物件上,然後旋轉這兩根手指,以叫用旋轉操作。 這通常會旋轉物件。

可以同時進行多種類型的操作。

當您讓物件回應操作時,可以讓物件看起來像有慣性。 這可讓您的物件模擬真實世界。 例如,當您在桌上推動書本時,如果推得夠用力,則在放開書本之後,書本還會繼續移動。 WPF 可讓您藉由在使用者的手指放開 物件之後引發操作事件來模擬此行為。

如需如何建立可讓使用者移動、調整大小和旋轉物件的應用程式的資訊,請參閱逐步解說:建立您的第一個觸控應用程式

UIElement會定義下列操作事件。

根據預設, UIElement 不會接收這些操作事件。 若要在 上 UIElement 接收操作事件,請將 設定 UIElement.IsManipulationEnabledtrue

操作事件的執行路徑

請考慮使用者「擲回」物件的情況。 使用者將手指放在物件上,並將手指移過觸控式螢幕的一小段距離,然後在移動時移開手指。 這樣的結果是會移動使用者手指下方的物件,並在使用者移開手指之後繼續移動。

下圖顯示操作事件的執行路徑以及每個事件的重要資訊。

The sequence of manipulation events. 操作事件

下列清單描述上圖中的事件順序。

  1. 當使用者 ManipulationStarting 將手指放在 物件上時,就會發生此事件。 除此之外,此事件可讓您設定 ManipulationContainer 屬性。 在後續事件中,操作的位置會相對於 ManipulationContainer 。 在 以外的 ManipulationStarting 事件中,這個屬性是唯讀的,因此 ManipulationStarting 事件是唯一可以設定此屬性的時間。

  2. 接下來 ManipulationStarted 就會發生此事件。 此事件會報告操作的原點。

  3. 當使用者的手指在觸控式螢幕上移動時,就會 ManipulationDelta 多次發生此事件。 類別 DeltaManipulationManipulationDeltaEventArgs 屬性會報告操作是否解譯為移動、展開或轉譯。 這是您執行大部分物件操作工作的位置。

  4. 當使用者 ManipulationInertiaStarting 的手指失去與物件的接觸時,就會發生此事件。 此事件可讓您指定慣性期間的操作減速。 因此,如果選擇的話,您的物件可以模擬不同的實體空間或屬性。 例如,假設應用程式有兩個物件代表真實世界中的項目,而且其中一個比另一個重。 您可以將較重的物件減速,使其比較輕的物件更快。

  5. 事件發生 ManipulationDelta 多次,因為慣性發生。 請注意,當使用者的手指在觸控式螢幕上移動,當 WPF 模擬慣性時,就會發生這個事件。 換句話說, ManipulationDelta 發生在事件前後 ManipulationInertiaStarting 。 屬性 ManipulationDeltaEventArgs.IsInertial 會報告事件是否 ManipulationDelta 在慣性期間發生,因此您可以根據屬性的值檢查該屬性並執行不同的動作。

  6. ManipulationCompleted 操作和任何慣性結束時,就會發生此事件。 也就是說,在發生所有 ManipulationDelta 事件之後, ManipulationCompleted 就會發生 事件,以表示操作已完成。

UIElement也會定義 ManipulationBoundaryFeedback 事件。 在 事件中 ManipulationDelta 呼叫 方法時 ReportBoundaryFeedback ,就會發生這個事件。 事件 ManipulationBoundaryFeedback 可讓應用程式或元件在物件達到界限時提供視覺回饋。 例如,類別會 Window 處理 ManipulationBoundaryFeedback 事件,以在遇到視窗邊緣時稍微移動。

您可以在事件以外的任何操作事件 ManipulationBoundaryFeedback 中呼叫 事件引數上的 方法,以取消操作 Cancel 。 當您呼叫 Cancel 時,不會再引發操作事件,而且觸控會發生滑鼠事件。 下表描述操作取消時間與所發生的滑鼠事件之間的關聯性。

其中呼叫 Cancel 的事件 針對已發生之輸入所發生的滑鼠事件
ManipulationStartingManipulationStarted 滑鼠向下事件。
ManipulationDelta 滑鼠向下和滑鼠移動事件。
ManipulationInertiaStartingManipulationCompleted 滑鼠向下、滑鼠移動和滑鼠向上事件。

請注意,如果您在操作處於慣性狀態時呼叫 Cancel ,方法會 false 傳回 ,而且輸入不會引發滑鼠事件。

觸控與操作事件之間的關聯性

UIElement 律可以接收觸控事件。 IsManipulationEnabled當 屬性設定為 true 時, UIElement 可以同時接收觸控和操作事件。 TouchDown如果未處理事件(也就是 Handled 屬性為 false ),操作邏輯會擷取元素的觸控並產生操作事件。 Handled如果 屬性在 事件中 TouchDown 設定為 true ,則操作邏輯不會產生操作事件。 下圖示範觸控事件與操作事件之間的關聯性。

Relationship between touch and manipulation events 觸控和操作事件

下列清單描述上圖中所顯示之觸控事件與操作事件間的關聯性。

焦點

WPF 中的焦點有兩個主要概念:鍵盤焦點和邏輯焦點。

鍵盤焦點

鍵盤焦點是指接收鍵盤輸入的項目。 整個桌面只能有一個項目有鍵盤焦點。 在 WPF 中,具有鍵盤焦點的專案將會 IsKeyboardFocused 設定為 true 。 靜態 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 焦點範圍中的 。 應用程式中可以有多個具有邏輯焦點的項目,但特定的焦點範圍中只能有一個有邏輯焦點的項目。

焦點範圍是可追蹤其範圍內 之 的 FocusedElement 容器專案。 當焦點離開焦點範圍時,焦點項目就會失去鍵盤焦點,但卻仍然保有邏輯焦點。 當焦點回到焦點範圍時,焦點項目就會取得鍵盤焦點。 這讓鍵盤焦點能在多個焦點範圍間變更,但確保焦點範圍內的焦點項目仍是焦點返回時的焦點項目。

元素可以藉由將附加屬性設定為 ,或使用 方法來設定 FocusManager 附加屬性 IsFocusScopetrueSetIsFocusScope ,以轉換成可延伸應用程式標記語言 (XAML) 中的焦點範圍。

下列範例會藉由設定 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);
Dim focuseScope2 As New StackPanel()
FocusManager.SetIsFocusScope(focuseScope2, True)

WPF 中的類別預設為 Window 、、 MenuToolBarContextMenu

具有鍵盤焦點的專案也會有其所屬焦點範圍的邏輯焦點:因此,使用 類別或 Keyboard 基底專案類別的 方法,將焦點設定為元素 Focus ,會嘗試提供元素鍵盤焦點和邏輯焦點。

若要判斷焦點範圍中的焦點專案,請使用 GetFocusedElement 。 若要變更焦點範圍的焦點專案,請使用 SetFocusedElement

如需邏輯焦點的詳細資訊,請參閱焦點概觀

滑鼠位置

WPF 輸入 API 提供有關座標空間的實用資訊。 例如,座標 (0,0) 是左上角的座標,但樹狀結構中的項目左上方為何? 為輸入目標的項目? 附加事件處理常式的項目? 或其他事項? 為了避免混淆,WPF 輸入 API 會要求您在處理透過滑鼠取得的座標時,指定參考框架。 方法 GetPosition 會傳回滑鼠指標相對於指定專案座標。

滑鼠捕捉

滑鼠裝置專門保留稱為滑鼠捕捉的強制回應特性。 滑鼠捕捉是用來維護啟動拖放作業後的轉換輸入狀態;因此,不一定會發生涉及滑鼠指標之額定螢幕位置的其他作業。 拖曳期間,使用者按一下就會中止拖放,這樣會在拖曳原點持有滑鼠捕捉時,讓大部分的 mouseover 提示為不適當。 輸入系統會公開可判斷滑鼠擷取狀態的 API,以及可將滑鼠擷取強制擷取至特定元素的 API,或清除滑鼠擷取狀態的 API。 如需拖放作業的詳細資訊,請參閱拖放概觀

命令

命令比裝置輸入更接近語意層級的輸入處理。 命令是簡單指示詞,例如 CutCopyPasteOpen。 命令適用於將命令邏輯集中。 相同的命令可以從 Menu 、在 上 ToolBar 或透過鍵盤快速鍵存取。 命令也提供一種機制,可在命令變成無法使用時停用控制項。

RoutedCommand 是 的 WPF 實作 ICommandRoutedCommand執行 時, PreviewExecuted 命令目標上會引發 和 Executed 事件,該目標會像其他輸入一樣透過專案樹狀結構進行通道和泡泡。 如果未設定命令目標,則具有鍵盤焦點的項目就是命令目標。 執行命令的邏輯會附加至 CommandBindingExecuted當事件到達 CommandBinding 該特定命令的 時, ExecutedRoutedEventHandler 會呼叫 上的 CommandBinding 。 此處理常式會執行命令的動作。

如需命令的詳細資訊,請參閱命令概觀

WPF 提供由 、、、、 NavigationCommandsEditingCommands 組成的通用命令 ApplicationCommands 程式庫,或者您可以 ComponentCommands 定義自己的命令。 MediaCommands

下列範例示範如何設定 MenuItem ,以便在按一下時,它會在 上 TextBoxPaste 用 命令,假設 TextBox 具有鍵盤焦點。

<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 中命令的詳細資訊,請參閱 命令概觀

輸入系統和基底項目

輸入事件,例如 、 KeyboardStylus 類別所 Mouse 定義的附加事件,是由輸入系統引發,並根據執行時間點擊測試視覺化樹狀結構,插入物件模型中的特定位置。

Keyboard 和 定義為附加事件的每個事件 Mouse ,也會由基底專案類別 UIElementContentElement 新的路由事件重新 Stylus 公開。 可處理原始附加事件並重複使用事件資料的類別會產生基底項目路由事件。

輸入事件透過其基底項目輸入事件實作與特定來源項目建立關聯時,可以透過事件路由的其餘部分進行路由傳送,而其乃根據邏輯和視覺化樹狀結構物件的組合,並透過應用程式碼進行處理。 一般而言,使用 和 ContentElement 上的 UIElement 路由事件來處理這些裝置相關的輸入事件比較方便,因為您可以在 XAML 和程式碼中使用更直覺的事件處理常式語法。 您可以選擇改為處理已初始程序的附加事件,但會遇到幾個問題︰基底項目類別處理可能會將附加事件標記為已處理,而且您需要使用存取子方法,而不是真正事件語法,才能附加所附加事件的處理常式。

後續步驟

您現在有數種處理 WPF 輸入的技術。 您也應該進一步瞭解各種輸入事件種類,以及 WPF 所使用的路由事件機制。

有其他資源可以更詳細地說明 WPF 架構元素和事件路由。 如需詳細資訊,請參閱下列概觀:命令概觀焦點概觀基底項目概觀WPF 中的樹狀結構路由事件概觀

另請參閱