焦點概觀Focus Overview

WPFWPF 中有兩個關於焦點的主要概念︰鍵盤焦點和邏輯焦點。In WPFWPF there are two main concepts that pertain to focus: keyboard focus and logical focus. 鍵盤焦點是指接收鍵盤輸入的項目,邏輯焦點是指焦點範圍中具有焦點的項目。Keyboard focus refers to the element that receives keyboard input and logical focus refers to the element in a focus scope that has focus. 本概觀會詳細討論這些概念。These concepts are discussed in detail in this overview. 了解這些概念的差異對建立複雜的應用程式很重要,這些應用程式有多個可取得焦點的區域。Understanding the difference in these concepts is important for creating complex applications that have multiple regions where focus can be obtained.

參與焦點管理的主要類別皆Keyboard類別,FocusManager類別和基底的項目,這類類別UIElementContentElementThe major classes that participate in focus management are the Keyboard class, the FocusManager class, and the base element classes, such as UIElement and ContentElement. 如需基底項目的詳細資訊,請參閱基底項目概觀For more information about the base elements, see the Base Elements Overview.

Keyboard類別有關主要與鍵盤焦點和FocusManager是著重於邏輯焦點,但這不是絕對的區別。The Keyboard class is concerned primarily with keyboard focus and the FocusManager is concerned primarily with logical focus, but this is not an absolute distinction. 具有鍵盤焦點的項目也會有邏輯焦點,但具有邏輯焦點的項目不一定有鍵盤焦點。An element that has keyboard focus will also have logical focus, but an element that has logical focus does not necessarily have keyboard focus. 當您使用很明顯Keyboard類別來設定它具有鍵盤焦點的項目也會設定邏輯焦點的項目上。This is apparent when you use the Keyboard class to set the element that has keyboard focus, for it also sets logical focus on the element.

鍵盤焦點Keyboard Focus

鍵盤焦點是指目前接收鍵盤輸入的項目。Keyboard focus refers to the element that is currently receiving keyboard input. 整個桌面只能有一個項目有鍵盤焦點。There can be only one element on the whole desktop that has keyboard focus. WPFWPF,具有鍵盤焦點的項目會有IsKeyboardFocused設定為trueIn WPFWPF, the element that has keyboard focus will have IsKeyboardFocused set to true. 靜態屬性FocusedElementKeyboard類別取得目前具有鍵盤焦點的項目。The static property FocusedElement on the Keyboard class gets the element that currently has keyboard focus.

為了讓項目取得鍵盤焦點FocusableIsVisible基底的項目上的屬性必須設為trueIn order for an element to obtain keyboard focus, the Focusable and the IsVisible properties on the base elements must be set to true. 部分類別,例如Panel基底類別,具有Focusable設為false預設值; 因此,您必須設定Focusabletrue如果您想要能夠取得鍵盤焦點的這類項目。Some classes, such as the Panel base class, have Focusable set to false by default; therefore, you must set Focusable to true if you want such an element to be able to obtain keyboard focus.

鍵盤焦點可以透過使用者與 UIUI 的互動取得,例如項目的定位處理,或以滑鼠按一下某些項目。Keyboard focus can be obtained through user interaction with the UIUI, such as tabbing to an element or clicking the mouse on certain elements. 鍵盤焦點,還可以取得以程式設計方式使用Focus方法Keyboard類別。Keyboard focus can also be obtained programmatically by using the Focus method on the Keyboard class. Focus方法會嘗試將指定的項目鍵盤焦點。The Focus method attempts to give the specified element keyboard focus. 傳回的項目是具有鍵盤焦點的項目,如果舊或新的焦點物件封鎖要求,這可能是不同於要求的項目。The returned element is the element that has keyboard focus, which might be a different element than requested if either the old or new focus object block the request.

下列範例會使用Focus方法上設定鍵盤焦點ButtonThe following example uses the Focus method to set keyboard focus on a Button.

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

IsKeyboardFocused基底的項目類別的屬性會取得值,指出項目是否有鍵盤焦點。The IsKeyboardFocused property on the base element classes gets a value indicating whether the element has keyboard focus. IsKeyboardFocusWithin基底的項目類別的屬性會取得值,指出項目,或任何一種 visual 其子項目是否具有鍵盤焦點。The IsKeyboardFocusWithin property on the base element classes gets a value indicating whether the element or any one of its visual child elements has keyboard focus.

當應用程式啟動時設定初始焦點,要接收焦點的項目必須在應用程式所載入之初始視窗的視覺化樹狀結構和元素必須有FocusableIsVisible設定為trueWhen setting initial focus at application startup, the element to receive focus must be in the visual tree of the initial window loaded by the application, and the element must have Focusable and IsVisible set to true. 設定初始焦點的建議的位置是在Loaded事件處理常式。The recommended place to set initial focus is in the Loaded event handler. ADispatcher回呼也用於藉由呼叫InvokeBeginInvokeA Dispatcher callback can also be used by calling Invoke or BeginInvoke.

邏輯焦點Logical Focus

邏輯焦點是指FocusManager.FocusedElement焦點範圍中。Logical focus refers to the FocusManager.FocusedElement in a focus scope. 焦點範圍是追蹤的項目FocusedElement其範圍內。A focus scope is an element that keeps track of the FocusedElement within its scope. 當鍵盤焦點離開焦點範圍時,焦點項目就會失去鍵盤焦點,但卻仍然保有邏輯焦點。When keyboard focus leaves a focus scope, the focused element will lose keyboard focus but will retain logical focus. 當鍵盤焦點回到焦點範圍時,焦點項目就會取得鍵盤焦點。When keyboard focus returns to the focus scope, the focused element will obtain keyboard focus. 這讓鍵盤焦點能在多個焦點範圍間變更,但確保當焦點回到集點範圍內時,焦點範圍內的焦點項目會重新取得鍵盤焦點。This allows for keyboard focus to be changed between multiple focus scopes but ensures that the focused element in the focus scope regains keyboard focus when focus returns to the focus scope.

應用程式中可以有多個具有邏輯焦點的項目,但特定的焦點範圍中只能有一個有邏輯焦點的項目。There can be multiple elements that have logical focus in an application, but there may only be one element that has logical focus in a particular focus scope.

具有鍵盤焦點的項目有其所屬焦點範圍的邏輯焦點。An element that has keyboard focus has logical focus for the focus scope it belongs to.

項目可以轉換成焦點範圍Extensible Application Markup Language (XAML)Extensible Application Markup Language (XAML)splittunnelingFocusManager附加屬性IsFocusScopetrueAn element can be turned into a focus scope in Extensible Application Markup Language (XAML)Extensible Application Markup Language (XAML) by setting the FocusManager attached property IsFocusScope to true. 在程式碼中的項目可以轉換成焦點範圍藉由呼叫SetIsFocusScopeIn code, an element can be turned into a focus scope by calling SetIsFocusScope.

下列範例會使StackPanel成焦點範圍,藉由設定IsFocusScope附加屬性。The following example makes a StackPanel into a focus scope by setting the IsFocusScope attached property.

<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)

GetFocusScope 傳回指定之項目的焦點範圍。GetFocusScope returns the focus scope for the specified element.

中的類別WPFWPF是焦點範圍,預設為WindowMenuItemToolBar,和ContextMenuClasses in WPFWPF which are focus scopes by default are Window, MenuItem, ToolBar, and ContextMenu.

GetFocusedElement 取得指定的焦點範圍的焦點項目。GetFocusedElement gets the focused element for the specified focus scope. SetFocusedElement 指定的焦點範圍中設定焦點的項目。SetFocusedElement sets the focused element in the specified focus scope. SetFocusedElement 通常用來設定初始焦點的項目。SetFocusedElement is typically used to set the initial focused element.

下例在焦點範圍中設定焦點項目,並取得焦點範圍的焦點項目。The following example sets the focused element on a focus scope and gets the focused element of a focus scope.

// 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);
' Sets the focused element in focusScope1
' focusScope1 is a StackPanel.
FocusManager.SetFocusedElement(focusScope1, button2)

' Gets the focused element for focusScope 1
Dim focusedElement As IInputElement = FocusManager.GetFocusedElement(focusScope1)

鍵盤導覽Keyboard Navigation

KeyboardNavigation類別會負責實作預設的鍵盤焦點導覽,按下其中一個導覽鍵時。The KeyboardNavigation class is responsible for implementing default keyboard focus navigation when one of the navigation keys is pressed. 導覽鍵是:索引鍵 索引標籤、 SHIFT + TAB、 CTRL + TAB、 CTRL + SHIFT + TAB、 UPARROW、 向下箭號、 LEFTARROW 和向右鍵。The navigation keys are: TAB, SHIFT+TAB, CTRL+TAB, CTRL+SHIFT+TAB, UPARROW, DOWNARROW, LEFTARROW, and RIGHTARROW keys.

設定附加也可以變更導覽容器的瀏覽行為KeyboardNavigation屬性TabNavigationControlTabNavigation,和DirectionalNavigationThe navigation behavior of a navigation container can be changed by setting the attached KeyboardNavigation properties TabNavigation, ControlTabNavigation, and DirectionalNavigation. 這些屬性都屬於類型KeyboardNavigationMode和可能的值為ContinueLocalContainedCycleOnce,和NoneThese properties are of type KeyboardNavigationMode and the possible values are Continue, Local, Contained, Cycle, Once, and None. 預設值是Continue,表示項目不是導覽容器。The default value is Continue, which means the element is not a navigation container.

下列範例會建立Menu數目的MenuItem物件。The following example creates a Menu with a number of MenuItem objects. TabNavigation附加的屬性設定為CycleMenuThe TabNavigation attached property is set to Cycle on the Menu. 使用 tab 鍵在變更焦點時Menu、 焦點會移動每個項目和最後一個項目到達時就會回到第一個項目。When focus is changed using the tab key within the Menu, focus will move from each element and when the last element is reached focus will return to the first element.

<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);
Dim navigationMenu As New Menu()
Dim item1 As New MenuItem()
Dim item2 As New MenuItem()
Dim item3 As New MenuItem()
Dim item4 As New MenuItem()

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

KeyboardNavigation.SetTabNavigation(navigationMenu, KeyboardNavigationMode.Cycle)

其他 api 來處理焦點MoveFocusPredictFocusAdditional API to work with focus are MoveFocus and PredictFocus.

MoveFocus 將焦點變更至應用程式中的下一個項目。MoveFocus changes focus to the next element in the application. ATraversalRequest用來指定的方向。A TraversalRequest is used to specify the direction. FocusNavigationDirection傳遞給MoveFocus指定的不同方向焦點可以移動,例如FirstLastUpDownThe FocusNavigationDirection passed to MoveFocus specifies the different directions focus can be moved, such as First, Last, Up and Down.

下列範例會使用MoveFocus變更焦點的項目。The following example uses MoveFocus to change the focused element.

// 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);
}
' Creating a FocusNavigationDirection object and setting it to a
' local field that contains the direction selected.
Dim focusDirection As FocusNavigationDirection = _focusMoveValue

' MoveFocus takes a TraveralReqest as its argument.
Dim request As New TraversalRequest(focusDirection)

' Gets the element with keyboard focus.
Dim elementWithFocus As UIElement = TryCast(Keyboard.FocusedElement, UIElement)

' Change keyboard focus.
If elementWithFocus IsNot Nothing Then
    elementWithFocus.MoveFocus(request)
End If

PredictFocus 傳回變更焦點時接收焦點的物件。PredictFocus returns the object which would receive focus if focus were to be changed. 目前,只有UpDownLeft,和Right受到PredictFocusCurrently, only Up, Down, Left, and Right are supported by PredictFocus.

焦點事件Focus Events

與鍵盤焦點相關的事件PreviewGotKeyboardFocusGotKeyboardFocusPreviewLostKeyboardFocusLostKeyboardFocusThe events related to keyboard focus are PreviewGotKeyboardFocus, GotKeyboardFocus and PreviewLostKeyboardFocus, LostKeyboardFocus. 事件上定義為附加事件Keyboard類別,但更容易存取做為基底的項目類別的對等路由事件。The events are defined as attached events on the Keyboard class, but are more readily accessible as equivalent routed events on the base element classes. 如需事件的詳細資訊,請參閱路由事件概觀For more information about events, see the Routed Events Overview.

GotKeyboardFocus 項目取得鍵盤焦點時引發。GotKeyboardFocus is raised when the element obtains keyboard focus. LostKeyboardFocus 項目失去鍵盤焦點時引發。LostKeyboardFocus is raised when the element loses keyboard focus. 如果PreviewGotKeyboardFocus事件或PreviewLostKeyboardFocusEvent處理事件並Handled設定為true,則不會變更焦點。If the PreviewGotKeyboardFocus event or the PreviewLostKeyboardFocusEvent event is handled and Handled is set to true, then focus will not change.

下列範例會將附加GotKeyboardFocusLostKeyboardFocus事件處理常式TextBoxThe following example attaches GotKeyboardFocus and LostKeyboardFocus event handlers to a 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取得鍵盤焦點Background屬性TextBox變更為LightBlueWhen the TextBox obtains keyboard focus, the Background property of the TextBox is changed to 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();
    }
}
Private Sub TextBoxGotKeyboardFocus(ByVal sender As Object, ByVal e As KeyboardFocusChangedEventArgs)
    Dim source As TextBox = TryCast(e.Source, TextBox)

    If source IsNot Nothing Then
        ' Change the TextBox color when it obtains focus.
        source.Background = Brushes.LightBlue

        ' Clear the TextBox.
        source.Clear()
    End If
End Sub

TextBox失去鍵盤焦點Background屬性TextBox變更回白色。When the TextBox loses keyboard focus, the Background property of the TextBox is changed back to white.

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();
    }
}
Private Sub TextBoxLostKeyboardFocus(ByVal sender As Object, ByVal e As KeyboardFocusChangedEventArgs)
    Dim source As TextBox = TryCast(e.Source, TextBox)

    If source IsNot Nothing Then
        ' Change the TextBox color when it loses focus.
        source.Background = Brushes.White

        ' Set the  hit counter back to zero and updates the display.
        Me.ResetCounter()
    End If
End Sub

與邏輯焦點相關的事件GotFocusLostFocusThe events related to logical focus are GotFocus and LostFocus. 這些事件上定義FocusManager為附加事件,但FocusManager不會公開 CLR 事件包裝函式。These events are defined on the FocusManager as attached events, but the FocusManager does not expose CLR event wrappers. UIElementContentElement更方便地公開 (expose) 這些事件。UIElement and ContentElement expose these events more conveniently.

另請參閱See also