共用方式為


焦點概觀

更新:2007 年 11 月

WPF 中有兩個關於焦點的主要概念:鍵盤焦點和邏輯焦點。鍵盤焦點是指收到鍵盤輸入的項目,而邏輯焦點則是指在焦點範圍中具有焦點的項目。本概觀將詳細討論這些概念。認識這些概念的差別,將對建立具有可取得焦點的多個區域的複雜應用程式十分有幫助。

參與焦點管理的主要類別包括 Keyboard 類別、FocusManager 類別以及基底項目類別,例如 UIElementContentElement。如需基底項目的詳細資訊,請參閱基底項目概觀

Keyboard 類別主要與鍵盤焦點相關,而 FocusManager 則主要與邏輯焦點相關,但這並不是絕對的分際。具有鍵盤焦點的項目也會具有邏輯焦點,但具有邏輯焦點的項目則不一定會具有鍵盤焦點。這在使用 Keyboard 類別設定具有鍵盤焦點的項目時可明顯看出,因為它也會在項目上設定邏輯焦點。

這個主題包含下列章節。

  • 鍵盤焦點
  • 邏輯焦點
  • 鍵盤巡覽
  • 利用程式設計方式巡覽焦點
  • 焦點事件
  • 相關主題

鍵盤焦點

鍵盤焦點是指目前收到鍵盤輸入的項目。在整個畫面上只能有一個項目具有鍵盤焦點。在 WPF 中,具有鍵盤焦點的項目的 IsKeyboardFocused 將會設成 true。Keyboard 類別上的靜態屬性 FocusedElement 會取得目前具有鍵盤焦點的項目。

為了要讓項目取得鍵盤焦點,基底項目上的 FocusableIsVisible 屬性必須設定為 true。有些如 Panel 基底類別的類別,預設會將 Focusable 設為 false,因此,如果要項目能夠取得鍵盤焦點,就必須將 Focusable 設為 true。

鍵盤焦點可透過與 UI 的使用者互動取得,例如使用 TAB 鍵巡覽到某個項目,或是在某些項目上按一下滑鼠。另外,也可以使用 Keyboard 類別上的 Focus 方法,以程式設計方式取得鍵盤焦點。Focus 方法會嘗試將鍵盤焦點交給指定項目。傳回的項目就是具有鍵盤焦點的項目,但如果舊的或新的焦點物件封鎖要求,則回傳的項目可能與原本要求的項目不同。

下列範例使用 Focus 方法,將鍵盤焦點設給 Button

private void OnLoaded(object sender, RoutedEventArgs e)
{
    // Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton);
}

基底項目類別上的 IsKeyboardFocused 屬性會取得值,指出項目是否具有鍵盤焦點。基底項目類別上的 IsKeyboardFocusWithin 會取得值,指出項目或其任何視覺化子項目是否具有鍵盤焦點。

設定應用程式啟動的初始焦點時,收到焦點的項目必須連接至 PresentationSource,而且該項目必須將 FocusableIsVisible 設為 true。設定初始焦點的建議位置是在 Loaded 事件處理常式。Dispatcher 回呼 (Callback) 也可以藉由呼叫 InvokeBeginInvoke 來使用。

邏輯焦點

邏輯焦點是指焦點範圍中的 FocusManager.FocusedElement。焦點範圍是一個項目,會持續追蹤範圍內的 FocusedElement。當鍵盤焦點離開焦點範圍時,具有焦點的項目會失去鍵盤焦點,但卻仍然保有邏輯焦點。當鍵盤焦點返回焦點範圍時,具有焦點的項目將會取得鍵盤焦點。這樣可以讓鍵盤焦點在多個焦點範圍間變更,但可以確保在焦點返回焦點範圍時,焦點範圍中的焦點項目會重新取得鍵盤焦點。

應用程式中可以有多個項目具有邏輯焦點,但在特定焦點範圍中只能有一個項目具有邏輯焦點。

具有鍵盤焦點的項目也具有所屬焦點範圍的邏輯焦點。

項目可以進入焦點範圍內的方法是,在可延伸標記語言 (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);

GetFocusScope 會傳回所指定項目的焦點範圍。

WPF 中預設是焦點範圍的類別有 WindowMenuItemToolBarContextMenu

GetFocusedElement 會取得所指定焦點範圍的焦點項目。SetFocusedElement 會設定所指定焦點範圍中的焦點項目。SetFocusedElement 則通常用來設定初始焦點項目。

下列範例會在焦點範圍設定焦點項目,並取得焦點範圍的焦點項目。

// Sets the focused element in focusScope1
// focusScope1 is a StackPanel.
FocusManager.SetFocusedElement(focusScope1, button2);

// Gets the focused element for focusScope 1
IInputElement focusedElement = FocusManager.GetFocusedElement(focusScope1);

鍵盤巡覽

當按下其中一個巡覽鍵時,KeyboardNavigation 類別會負責實作預設鍵盤焦點巡覽。巡覽鍵有:TAB、SHIFT+TAB、CTRL+TAB、CTRL+SHIFT+TAB 鍵、向上、向下、向左和向右鍵。

巡覽容器的巡覽行為可藉由設定附加 KeyboardNavigation 屬性 TabNavigationControlTabNavigationDirectionalNavigation 來變更。這些屬性的型別為 KeyboardNavigationMode,可能的值包括 ContinueLocalContainedCycleOnceNone。預設值為 Continue,這表示項目不是巡覽容器。

下列範例會建立一個 Menu,其有數個 MenuItem 物件。TabNavigation 附加屬性會設為 Menu 上的 Cycle。在 Menu 內使用 Tab 鍵變更焦點時,焦點會從每個項目移動,當達到最後一個項目時,焦點就會回到第一個項目。

<Menu KeyboardNavigation.TabNavigation="Cycle">
  <MenuItem Header="Menu Item 1" />
  <MenuItem Header="Menu Item 2" />
  <MenuItem Header="Menu Item 3" />
  <MenuItem Header="Menu Item 4" />
</Menu>
Menu navigationMenu = new Menu();
MenuItem item1 = new MenuItem();
MenuItem item2 = new MenuItem();
MenuItem item3 = new MenuItem();
MenuItem item4 = new MenuItem();

navigationMenu.Items.Add(item1);
navigationMenu.Items.Add(item2);
navigationMenu.Items.Add(item3);
navigationMenu.Items.Add(item4);

KeyboardNavigation.SetTabNavigation(navigationMenu, 
    KeyboardNavigationMode.Cycle);

利用程式設計方式巡覽焦點

其他與焦點相關的 API 還有 MoveFocusPredictFocus

MoveFocus 會將焦點切換到應用程式中的下一個項目。TraversalRequest 是用來指定方向。傳遞至 MoveFocusFocusNavigationDirection 會指定焦點可移動的不同方向,例如 FirstLastUpDown

下列範例使用 MoveFocus 變更焦點項目。如需這個範例的完整原始程式碼,請參閱以程式設計方式操作焦點範例

// Creating a FocusNavigationDirection object and setting it to a
// local field that contains the direction selected.
FocusNavigationDirection focusDirection = _focusMoveValue;

// MoveFocus takes a TraveralReqest as its argument.
TraversalRequest request = new TraversalRequest(focusDirection);

// Gets the element with keyboard focus.
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;

// Change keyboard focus.
if (elementWithFocus != null)
{
    elementWithFocus.MoveFocus(request);
}

PredictFocus 會傳回變更焦點時將接收焦點的項目。目前,PredictFocus 只支援 UpDownLeftRight

焦點事件

與鍵盤焦點相關的事件有 PreviewGotKeyboardFocusGotKeyboardFocusPreviewLostKeyboardFocusLostKeyboardFocus。這些事件會定義為 Keyboard 類別上的附加事件,但當做基底項目類別上的對等路由事件會更容易存取。如需事件的詳細資訊,請參閱路由事件概觀

當項目取得鍵盤焦點時,會引發 GotKeyboardFocus。當項目失去鍵盤焦點時,則會引發 LostKeyboardFocus。如果 PreviewGotKeyboardFocus 事件或 PreviewLostKeyboardFocusEvent 事件已處理,並將 Handled 設為 true,則焦點不會變更。

下列範例將 GotKeyboardFocusLostKeyboardFocus 事件處理常式附加到 TextBox

<Border BorderBrush="Black" BorderThickness="1"
        Width="200" Height="100" Margin="5">
  <StackPanel>
    <Label HorizontalAlignment="Center" Content="Type Text In This TextBox" />
    <TextBox Width="175"
             Height="50" 
             Margin="5"
             TextWrapping="Wrap"
             HorizontalAlignment="Center"
             VerticalScrollBarVisibility="Auto"
             GotKeyboardFocus="TextBoxGotKeyboardFocus"
             LostKeyboardFocus="TextBoxLostKeyboardFocus"
             KeyDown="SourceTextKeyDown"/>
  </StackPanel>
</Border>

TextBox 取得鍵盤焦點時,TextBoxBackground 屬性會變成 LightBlue

private void TextBoxGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    TextBox source = e.Source as TextBox;

    if (source != null)
    {
        // Change the TextBox color when it obtains focus.
        source.Background = Brushes.LightBlue;

        // Clear the TextBox.
        source.Clear();
    }
}

TextBox 失去鍵盤焦點時,TextBoxBackground 屬性會變回白色。

private void TextBoxLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    TextBox source = e.Source as TextBox;

    if (source != null)
    {
        // Change the TextBox color when it loses focus.
        source.Background = Brushes.White;

        // Set the  hit counter back to zero and updates the display.
        this.ResetCounter();
    }
}

與邏輯焦點相關的事件有 GotFocusLostFocus。這些事件會在 FocusManager 上定義為附加屬性,但 FocusManager 不會公開 CLR 事件包裝函式。UIElementContentElement 能更方便公開這些事件。

請參閱

概念

輸入概觀

基底項目概觀

參考

FocusManager

UIElement

ContentElement