使用鍵盤、遊戲台、遙控器和協助工具進行的焦點瀏覽

Keyboard, remote, and D-pad

使用焦點瀏覽在 Windows 應用程式中提供全面且一致的互動體驗,並為鍵盤進階使用者、身障人士和其他有協助工具要求的使用者提供自訂控制項,以及電視螢幕和 Xbox One 的 10 英呎體驗。

概觀

焦點瀏覽是指使用者能夠使用鍵盤、遊戲台或遙控器瀏覽 Windows 應用程式的 UI 並與其互動的基礎機制。

注意

輸入裝置通常分類為指向裝置 (例如:觸控、觸控板、手寫筆和滑鼠) 以及非指向裝置 (例如:鍵盤、遊戲台和遙控器)。

本主題介紹如何最佳化 Windows 應用程式,並為依賴非指向輸入類型的使用者建立自訂互動體驗。

雖然我們專注於電腦上 Windows 應用程式中自訂控制項的鍵盤輸入,但精心設計的鍵盤體驗對於觸控式鍵盤和螢幕小鍵盤 (OSK) 等軟體鍵盤也很重要,支援 Windows 朗讀程式等協助工具,以及支援 10 英呎體驗。

如需在 Windows 應用程式中為指向裝置建立自訂體驗的指引,請參閱處理指標輸入

如需建立鍵盤應用程式和體驗的一般資訊,請參閱鍵盤互動

一般方針

只有那些需要使用者互動的 UI 元素才應支援焦點瀏覽,不需要動作的元素 (例如:靜態影像) 不需要鍵盤焦點。 螢幕助讀程式和類似的協助工具仍然會宣告這些靜態元素,即使它們未包含在焦點瀏覽中也一樣。

請務必記住,與使用滑鼠或觸控等指標裝置瀏覽不同,焦點瀏覽是線性的。 實作焦點瀏覽時,請考慮使用者如何與您的應用程式互動,以及邏輯瀏覽應該是什麼。 在大部分情況下,我們建議自訂焦點瀏覽行為遵循使用者文化特性的慣用閱讀模式。

其他一些焦點瀏覽考量包括:

  • 控制項是否按邏輯分組?
  • 是否有更重要的控制組?
    • 如果是,這些群組是否包含子群組?
  • 版面配置是否需要自訂方向瀏覽 (箭頭鍵) 和定位順序?

適用於協助工具的工程軟體電子書有一個關於設計邏輯階層的精彩章節。

鍵盤的 2D 方向瀏覽

控制項或控制項群組的 2D 內部瀏覽區域稱為其「方向區域」。 當焦點轉移到這個物件時,鍵盤箭頭鍵 (向左、向右、向上和向下) 可用來在方向區域內的子元素之間瀏覽。

directional area控制項群組的 2D 內部瀏覽區域或方向區域

您可以使用 XYFocusKeyboardNavigation 屬性 (其可能值為 AutoEnabledDisabled) 使用鍵盤方向鍵來管理 2D 內部瀏覽。

注意

定位順序不會受到這個屬性的影響。 為了避免混淆的瀏覽體驗,建議不要在應用程式的定位瀏覽順序中明確指定方向區域的子元素。 如需元素定位處理行為的詳細資訊,請參閱 UIElement.TabFocusNavigationTabIndex 屬性。

Auto (預設行為)

當設定為 Auto 時,方向瀏覽行為是由元素的上階或繼承階層所決定。 如果所有上階都處於預設模式 (設定為 Auto),則不支援使用鍵盤進行方向瀏覽。

停用

XYFocusKeyboardNavigation 設定為 Disabled,以封鎖控制項及其子元素的方向瀏覽。

XYFocusKeyboardNavigation disabled behaviorXYFocusKeyboardNavigation 停用行為

在此範例中,主要 StackPanel (ContainerPrimary) 已 將 XYFocusKeyboardNavigation 設定為 Enabled。 所有子元素都會繼承此設定,而且可以使用方向鍵瀏覽。 不過,B3 和 B4 元素位於次要 StackPanel (ContainerSecondary) 中,其中 XYFocusKeyboardNavigation 設定為 Disabled,這會覆寫主要容器,並停用本身及其子元素之間的方向鍵瀏覽。

<Grid 
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" 
    TabFocusNavigation="Cycle">
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="75"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock Name="KeyPressed"
                Grid.Row="0" 
                FontWeight="ExtraBold" 
                HorizontalTextAlignment="Center"
                TextWrapping="Wrap" 
                Padding="10" />
    <StackPanel Name="ContainerPrimary" 
                XYFocusKeyboardNavigation="Enabled" 
                KeyDown="ContainerPrimary_KeyDown" 
                Orientation="Horizontal" 
                BorderBrush="Green" 
                BorderThickness="2" 
                Grid.Row="1" 
                Padding="10" 
                MaxWidth="200">
        <Button Name="B1" 
                Content="B1" 
                GettingFocus="Btn_GettingFocus" />
        <Button Name="B2" 
                Content="B2" 
                GettingFocus="Btn_GettingFocus" />
        <StackPanel Name="ContainerSecondary" 
                    XYFocusKeyboardNavigation="Disabled" 
                    Orientation="Horizontal" 
                    BorderBrush="Red" 
                    BorderThickness="2">
            <Button Name="B3" 
                    Content="B3" 
                    GettingFocus="Btn_GettingFocus" />
            <Button Name="B4" 
                    Content="B4" 
                    GettingFocus="Btn_GettingFocus" />
        </StackPanel>
    </StackPanel>
</Grid>

已啟用

XYFocusKeyboardNavigation 設定為 Enabled,以支援控制項及其每個 UIElement 子物件的 2D 方向瀏覽。

設定後,使用方向鍵瀏覽僅限於方向區域內的元素。 定位瀏覽不會受到影響,因為所有控制件仍可透過定位順序階層存取。

XYFocusKeyboardNavigation enabled behaviorXYFocusKeyboardNavigation 啟用行為

在此範例中,主要 StackPanel (ContainerPrimary) 已 將 XYFocusKeyboardNavigation 設定為 Enabled。 所有子元素都會繼承此設定,而且可以使用方向鍵瀏覽。 B3 和 B4 元素位於次要 StackPanel (ContainerSecondary) 中,其中 XYFocusKeyboardNavigation 未設定,然後繼承主要容器設定。 B5 元素不在宣告的方向區域內,且不支援方向鍵瀏覽,但支援標準定位瀏覽行為。

<Grid
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    TabFocusNavigation="Cycle">
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="100"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock Name="KeyPressed"
               Grid.Row="0"
               FontWeight="ExtraBold"
               HorizontalTextAlignment="Center"
               TextWrapping="Wrap"
               Padding="10" />
    <StackPanel Grid.Row="1"
                Orientation="Horizontal"
                HorizontalAlignment="Center">
        <StackPanel Name="ContainerPrimary"
                    XYFocusKeyboardNavigation="Enabled"
                    KeyDown="ContainerPrimary_KeyDown"
                    Orientation="Horizontal"
                    BorderBrush="Green"
                    BorderThickness="2"
                    Padding="5" Margin="5">
            <Button Name="B1"
                    Content="B1"
                    GettingFocus="Btn_GettingFocus" Margin="5" />
            <Button Name="B2"
                    Content="B2"
                    GettingFocus="Btn_GettingFocus" />
            <StackPanel Name="ContainerSecondary"
                        Orientation="Horizontal"
                        BorderBrush="Red"
                        BorderThickness="2"
                        Margin="5">
                <Button Name="B3"
                        Content="B3"
                        GettingFocus="Btn_GettingFocus"
                        Margin="5" />
                <Button Name="B4"
                        Content="B4"
                        GettingFocus="Btn_GettingFocus"
                        Margin="5" />
            </StackPanel>
        </StackPanel>
        <Button Name="B5"
                Content="B5"
                GettingFocus="Btn_GettingFocus"
                Margin="5" />
    </StackPanel>
</Grid>

您可以有多個巢狀方向區域層級。 如果所有父元素都已將 XYFocusKeyboardNavigation 設定為 Enabled,則會忽略內部瀏覽區域界限。

以下是元素內兩個巢狀方向區域的範例,其中未明確支援 2D 方向瀏覽。 在此情況下,兩個巢狀區域之間不支援方向瀏覽。

XYFocusKeyboardNavigation enabled and nested behaviorXYFocusKeyboardNavigation 啟用和巢狀行為

以下是三個巢狀方向區域的較複雜範例,其中:

  • 當 B1 具有焦點時,只能瀏覽到 B5 (反之亦然),因為有一個方向區域界限,其中 XYFocusKeyboardNavigation 設定為 Disabled,使得使用方向鍵無法到達 B2、B3 和 B4
  • 當 B2 具有焦點時,只能瀏覽到 B3 (反之亦然),因為方向區域界限會防止方向鍵瀏覽至 B1、B4 和 B5
  • 當 B4 具有焦點時,必須使用 Tab 鍵在控制項之間瀏覽

XYFocusKeyboardNavigation enabled and complex nested behavior

XYFocusKeyboardNavigation 啟用且複雜的巢狀行為

索引標籤導覽

雖然方向鍵可用於控制項或控制項群組的 2D 方向瀏覽,但 Tab 鍵可用來在 Windows 應用程式中的所有控制項之間瀏覽。

預設情況下,所有互動式控制項都支援 Tab 鍵瀏覽 (IsEnabledIsTabStop 屬性為 true),邏輯定位順序源自應用程式中的控制項配置。 不過,預設順序不一定對應至視覺順序。 實際顯示位置可能取決於父版面配置容器,以及您可以在子元素上設定以影響配置的某些屬性。

避免使用會使焦點在應用程式中跳躍的自訂定位順序順序。 例如,表單中的控制項清單應該有從上到下和從左至右移動的定位順序 (視地區設定而定)。

在本節中,我們將說明如何完全自訂此定位順序以符合您的應用程式。

設定定位瀏覽行為

UIElementTabFocusNavigation 屬性會指定其整個物件樹狀結構 (或方向區域) 的定位瀏覽行為。

注意

對於不使用 ControlTemplate 定義其外觀的物件,請使用此屬性而不是 Control.TabNavigation 屬性。

如上一節所述,為了避免混淆的瀏覽體驗,建議不要在應用程式的定位瀏覽順序中明確指定方向區域的子元素。 如需元素定位處理行為的詳細資訊,請參閱 UIElement.TabFocusNavigationTabIndex 屬性。

對於 Windows 10 Creators Update 之前的版本 (組建 10.0.15063),定位設定僅限於 ControlTemplate 物件。 如需詳細資訊,請參閱 Control.TabNavigation

TabFocusNavigation 具有 KeyboardNavigationMode 類型的值,具有以下可能值 (請注意,這些範例不是自訂控制項撙,不需要使用方向鍵進行內部瀏覽):

  • 本機 (預設) 定位索引會在容器內的本機子樹狀結構上辨識。 在此範例中,定位順序為 B1、B2、B3、B4、B5、B6、B7、B1。

    "Local" 定位瀏覽行為

  • Once 容器和所有子元素都接收焦點一次。 在此範例中,定位順序為 B1、B2、B7、B1 (也示範使用方向鍵的內部瀏覽)。

    "Once" 定位瀏覽行為

  • 循環
    焦點會循環回到容器內的初始可設定焦點的元素。 在此範例中,定位順序為 B1、B2、B3、B4、B5、B6、B2...

    "Cycle" 定位瀏覽行為

以下是上述範例的程序碼 (使用 TabFocusNavigation ="Cycle")。

<Grid 
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" 
    TabFocusNavigation="Cycle">
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="300"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock Name="KeyPressed"
               Grid.Row="0" 
               FontWeight="ExtraBold" 
               HorizontalTextAlignment="Center"
               TextWrapping="Wrap" 
               Padding="10" />
    <StackPanel Name="ContainerPrimary"
                KeyDown="Container_KeyDown" 
                Orientation="Horizontal" 
                HorizontalAlignment="Center"
                BorderBrush="Green" 
                BorderThickness="2" 
                Grid.Row="1" 
                Padding="10" 
                MaxWidth="200">
        <Button Name="B1" 
                Content="B1" 
                GettingFocus="Btn_GettingFocus" 
                Margin="5"/>
        <StackPanel Name="ContainerSecondary" 
                    KeyDown="Container_KeyDown"
                    XYFocusKeyboardNavigation="Enabled" 
                    TabFocusNavigation ="Cycle"
                    Orientation="Vertical" 
                    VerticalAlignment="Center"
                    BorderBrush="Red" 
                    BorderThickness="2"
                    Padding="5" Margin="5">
            <Button Name="B2" 
                    Content="B2" 
                    GettingFocus="Btn_GettingFocus" 
                    Margin="5"/>
            <Button Name="B3" 
                    Content="B3" 
                    GettingFocus="Btn_GettingFocus" 
                    Margin="5"/>
            <Button Name="B4" 
                    Content="B4" 
                    GettingFocus="Btn_GettingFocus" 
                    Margin="5"/>
            <Button Name="B5" 
                    Content="B5" 
                    GettingFocus="Btn_GettingFocus" 
                    Margin="5"/>
            <Button Name="B6" 
                    Content="B6" 
                    GettingFocus="Btn_GettingFocus" 
                    Margin="5"/>
        </StackPanel>
        <Button Name="B7" 
                Content="B7" 
                GettingFocus="Btn_GettingFocus" 
                Margin="5"/>
    </StackPanel>
</Grid>

TabIndex

使用 TabIndex 指定當使用者使用 Tab 鍵瀏覽控制項時,元素接收焦點的順序。 定位索引較低的控制項會在定位索引較高的控制項之前收到焦點。

當控制項未指定 TabIndex 時,將根據範圍為其指派比可視化樹狀結構中所有互動式控制項的目前最高索引值 (和最低優先順序) 更高的索引值。

控制項的所有子元素都被視為一個範圍,如果其中一個元素也有子元素,則會被視為另一個範圍。 透過選擇範圍可視化樹狀結構上的第一個元素來解決任何歧義。

若要從定位順序排除控制項,請將 IsTabStop 屬性設定為 false

藉由設定 TabIndex 屬性來覆寫預設定位順序。

注意

TabIndexUIElement.TabFocusNavigationControl.TabNavigation 的運作方式相同。

在這裡,我們將示範特定元素上的 TabIndex 屬性如何影響焦點瀏覽。

"Local" 定位瀏覽具有 TabIndex 行為

在先前的範例中,有兩個範圍:

  • B1、方向區域 (B2 - B6) 和 B7
  • 方向區域 (B2 - B6)

當 B3 (在方向區域中) 取得焦點時,範圍會變更,而定位瀏覽會傳輸到識別出後續焦點的最佳候選區域。 在此情況下,B2 之後是 B4、B5 和 B6。 範圍會再次變更,焦點移至 B1。

這是此範例的程式碼。

<Grid
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    TabFocusNavigation="Cycle">
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="300"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock Name="KeyPressed"
               Grid.Row="0"
               FontWeight="ExtraBold"
               HorizontalTextAlignment="Center"
               TextWrapping="Wrap"
               Padding="10" />
    <StackPanel Name="ContainerPrimary"
                KeyDown="Container_KeyDown"
                Orientation="Horizontal"
                HorizontalAlignment="Center"
                BorderBrush="Green"
                BorderThickness="2"
                Grid.Row="1"
                Padding="10"
                MaxWidth="200">
        <Button Name="B1"
                Content="B1"
                TabIndex="1"
                ToolTipService.ToolTip="TabIndex = 1"
                GettingFocus="Btn_GettingFocus"
                Margin="5"/>
        <StackPanel Name="ContainerSecondary"
                    KeyDown="Container_KeyDown"
                    TabFocusNavigation ="Local"
                    Orientation="Vertical"
                    VerticalAlignment="Center"
                    BorderBrush="Red"
                    BorderThickness="2"
                    Padding="5" Margin="5">
            <Button Name="B2"
                    Content="B2"
                    GettingFocus="Btn_GettingFocus"
                    Margin="5"/>
            <Button Name="B3"
                    Content="B3"
                    TabIndex="3"
                    ToolTipService.ToolTip="TabIndex = 3"
                    GettingFocus="Btn_GettingFocus"
                    Margin="5"/>
            <Button Name="B4"
                    Content="B4"
                    GettingFocus="Btn_GettingFocus"
                    Margin="5"/>
            <Button Name="B5"
                    Content="B5"
                    GettingFocus="Btn_GettingFocus"
                    Margin="5"/>
            <Button Name="B6"
                    Content="B6"
                    GettingFocus="Btn_GettingFocus"
                    Margin="5"/>
        </StackPanel>
        <Button Name="B7"
                Content="B7"
                TabIndex="2"
                ToolTipService.ToolTip="TabIndex = 2"
                GettingFocus="Btn_GettingFocus"
                Margin="5"/>
    </StackPanel>
</Grid>

鍵盤、遊戲台和遙控器的 2D 方向瀏覽

非指向輸入類型 (例如:鍵盤、遊戲台、遙控器) 和協助工具 (例如:Windows 朗讀程式) 共用通用的基礎機制,可用來瀏覽 Windows 應用程式的 UI 並與其互動。

在本節中,我們將介紹如何透過一組支援所有基於焦點的非指向輸入類型的瀏覽策略屬性,來指定偏好的瀏覽策略並在應用程式中微調焦點瀏覽。

如需建置 Xbox/電視應用程式和體驗的一般資訊,請參閱鍵盤互動Xbox 和電視設計,以及遊戲台和遙控器互動

瀏覽策略適用於鍵盤、遊戲台、遙控器和各種協助工具。

下列流覽策略屬性可讓您根據箭頭鍵、方向鍵 (D-pad) 按鈕或類似按下,影響哪些控件會收到焦點。

  • XYFocusUpNavigationStrategy
  • XYFocusDownNavigationStrategy
  • XYFocusLeftNavigationStrategy
  • XYFocusRightNavigationStrategy

這些屬性的可能值為 Auto (預設)、NavigationDirectionDistanceProjectionRectilinearDistance

如果設定為 Auto,元素的行為會以元素的上階為基礎。 如果所有元素都設定為 Auto,則會使用 Projection

注意

其他因素 (例如:先前具有焦點的元素或瀏覽方向軸的附近) 可能會影響結果。

Projection

當目前具有焦點的元素之邊緣在瀏覽方向投影時,投影策略會將焦點移動到遇到的第一個元素。

在此範例中,每個焦點瀏覽方向都會設定為 [投影]。 請注意焦點如何從 B1 向下移動至 B4,繞過 B3。 這是因為 B3 不在投影區域中。 另請注意,從 B1 向左移動時,無法識別焦點候選元素。 這是因為 B2 相對於 B1 的位置會排除 B3 做為候選元素。 如果 B3 與 B2 位於相同的資料列中,則它為左側瀏覽的可行候選元素。 B2 是可行的候選元素,因為它無阻礙地靠近瀏覽方向軸。

Projection navigation strategy

投影瀏覽策略

NavigationDirectionDistance 策略會將焦點移至最接近瀏覽方向軸的元素。

瀏覽方向對應的邊界矩形的邊緣會延伸投影來識別候選元素。 遇到的第一個元素會識別為目標。 在多個候選元素的情況下,最接近的元素會識別為目標。 如果仍有多個候選元素,則會將最上層/最左邊的元素識別為候選元素。

NavigationDirectionDistance navigation strategy

NavigationDirectionDistance 瀏覽策略

RectilinearDistance

RectilinearDistance 策略會根據 2D 直線距離 (Taxicab geometry) 將焦點移至最接近的元素。

每個潛在候選元素的主要距離和次要距離之總和用於識別最佳候選元素。 在平局中,如果要求的方向是向上或向下,則選擇左側的第一個元素;如果要求的方向是向左或向右,則選擇頂部的第一個元素。

RectilinearDistance navigation strategy

RectilinearDistance 瀏覽策略

此圖片顯示 B1 具有焦點並且要求的方向是向下時,B3 是 RectilinearDistance 焦點候選元素。 以下是基於此範例的計算:

  • 距離 (B1,B3,向下) 是 10 + 0 = 10
  • 距離 (B1,B2,向下) 是 0 + 40 = 40
  • 距離 (B1, D, 向下) 是 30 + 0 = 30