鍵盤協助工具

如果應用程式沒有提供良好的鍵盤協助工具,可能會導致盲人或行動不便的使用者難以甚至完全無法使用。

UI 元素之間的鍵盤瀏覽

若要搭配控制項使用鍵盤,控制項必須設有焦點;而要接收焦點 (不使用游標),該控制項在 UI 設計中必須能夠透過 Tab 鍵導覽存取。 根據預設,控制項的定位順序與其新增至設計平面的順序 (如 XAML 中所列) 或以程式設計方式新增至容器的順序相同。

在大多數情況下,基於 XAML 中控制項定義方式的預設順序會是最佳順序,主要原因在於這是螢幕助讀程式閱讀控制項的順序。 不過,預設順序不一定對應至視覺順序。 實際顯示位置可能取決於父版面配置容器,以及您可以在子元素上設定以影響配置的某些屬性。 為了確保應用程式具有良好的定位順序,請自行測試此行為。 特別是,如果您的版面配置隱含了網格或資料表,可能會導致使用者的閱讀順序與定位順序不同。 有時,這種情況本身不見得會構成問題。 然而,請務必同時測試應用程式的可觸控 UI 和鍵盤存取 UI 功能,並確認 UI 在兩種情況下都能合理運作。

您可以藉由調整 XAML,讓定位順序與視覺順序相符。 或者,您可以藉由設定 TabIndex 屬性來覆寫預設的定位順序,如下方使用資料欄優先 Tab 鍵導覽的 Grid 版面配置範例所示。

XAML

<!--Custom tab order.-->
<Grid>
  <Grid.RowDefinitions>...</Grid.RowDefinitions>
  <Grid.ColumnDefinitions>...</Grid.ColumnDefinitions>

  <TextBlock Grid.Column="1" HorizontalAlignment="Center">Groom</TextBlock>
  <TextBlock Grid.Column="2" HorizontalAlignment="Center">Bride</TextBlock>

  <TextBlock Grid.Row="1">First name</TextBlock>
  <TextBox x:Name="GroomFirstName" Grid.Row="1" Grid.Column="1" TabIndex="1"/>
  <TextBox x:Name="BrideFirstName" Grid.Row="1" Grid.Column="2" TabIndex="3"/>

  <TextBlock Grid.Row="2">Last name</TextBlock>
  <TextBox x:Name="GroomLastName" Grid.Row="2" Grid.Column="1" TabIndex="2"/>
  <TextBox x:Name="BrideLastName" Grid.Row="2" Grid.Column="2" TabIndex="4"/>
</Grid>

您可能想要從定位順序中排除特定的控制項。 通常,您只能透過將控制項設為非互動式來實現此目的,例如將其 IsEnabled 屬性設為 false。 已停用的控制項會自動從定位順序中排除。 然而,有時即使控制項尚未停用,您可能仍希望將其從定位順序中排除。 在這種情況下,您可以將 IsTabStop 屬性設為 false

任何可以獲得焦點的元素,通常都會預設加入定位順序。 一個例外情況是,有些文字顯示類型 (例如 RichTextBlock) 可以取得焦點,讓剪貼簿可以存取它們以選取文字;但它們並未加入定位順序,因為靜態文字元素不應出現在定位順序中。 它們不是傳統意義上的互動式元素 (無法叫用,而且不需要文字輸入,但確實支援文字控制項模式,也就是支援在文字中尋找並調整選取點)。 文字不應具有「取得焦點之後,即可進行一些可能的操作」這樣的含義。 輔助技術仍能偵測到文字元素,並在螢幕助讀程式中大聲讀出,但這必須仰賴其他技術,而不是按照實際的定位順序找到這些元素。

無論您選擇調整 TabIndex 值或使用預設順序,以下規則都適用:

  • 如果未在元素上設定 TabIndex,則會使用 Int32.MaxValue 做為預設值,而定位順序將以 XAML 或子集合中的宣告順序為基礎。
  • 如果在元素上設定了 TabIndex
    • TabIndex 等於 0 的 UI 元素會根據其在 XAML 或子集合中的宣告順序,新增至定位順序。
    • TabIndex 大於 0 的 UI 元素會根據 TabIndex 值,新增至定位順序。
    • TabIndex 小於 0 的 UI 元素會新增至定位順序,並顯示在任何零值之前。 這可能不同於 HTML 處理其 tabindex 屬性的方法 (舊版 HTML 規格不支援負的 tabindex)。

例如,以下程式碼片段顯示了具有不同 TabIndex 設定的元素集合 (B 被指派了 Int32.MaxValue 值,即 2,147,483,647)。

<StackPanel Background="#333">
  <StackPanel Background="#FF33FF">
    <Button>A</Button>
    <Button TabIndex="2147483647">B</Button>
    <Button>C</Button>
  </StackPanel>
  <StackPanel Background="#33FFFF">
    <Button TabIndex="1">D</Button>
    <Button TabIndex="1">E</Button>
    <Button TabIndex="0">F</Button>
  </StackPanel>
</StackPanel>

這會產生以下定位順序:

  1. F
  2. D
  3. E
  4. A
  5. B
  6. C

UI 元素內部的鍵盤導覽

針對複合元素,確保其所含元素之間的內部導覽正確無誤,可說是至關重要。 複合元素有能力管理其目前作用中的子元素,以減少讓所有子元素都能獲得焦點的負擔。 這類複合元素會包含在定位順序中,且本身就有能力處理鍵盤導覽事件。 許多複合控制項已經在自身的事件處理方法中內建了一些內部導覽邏輯。 例如,使用方向鍵周遊項目的功能會在 ListViewGridViewListBoxFlipView 控制項上預設啟用。

特定控制項元素之遊標動作和事件的鍵盤替代方案

請確保可點選的 UI 元素也可以使用鍵盤叫用。 只有設有焦點的 UI 元素,才能搭配鍵盤使用。 只有衍生自 Control 的類別,才支援焦點和 Tab 鍵導覽。

針對可叫用的 UI 元素,請為空白鍵和 Enter 鍵實作鍵盤事件處理常式。 如此便完成了基本的鍵盤協助工具支援,讓使用者只需使用鍵盤,就能完成基本的應用程式場景;也就是說,使用者可以存取所有互動式 UI 元素,並啟動預設功能。

如果您想要讓在 UI 中使用的元素無法獲得焦點,可以自行建立自訂控制項。 您必須將 IsTabStop 屬性設定為 true,以啟用焦點;另外還需要建立視覺狀態 (用焦點指標裝飾 UI),以提供焦點狀態的視覺指示。 不過,使用控制項組合通常較為方便,因為如此一來對於定位點、焦點和 Microsoft UI 自動化對等和模式之支援,將由您選擇在其中組合內容的控制項來處理。

例如,與其在 Image 上處理遊標按下事件,不如將該元素封裝在 Button 中,以獲得遊標、鍵盤和焦點支援。

XAML

<!--Don't do this.-->
<Image Source="sample.jpg" PointerPressed="Image_PointerPressed"/>

<!--Do this instead.-->
<Button Click="Button_Click"><Image Source="sample.jpg"/></Button>

鍵盤快速鍵

除了為應用程式實作鍵盤導覽和啟用功能外,為應用程式功能實作快捷鍵也是很好的做法。 Tab 鍵導覽提供了良好的基本鍵盤支持,但對於更複雜的表單,您可能還想要添加對快捷鍵的支援。 這可以讓您的應用程式使用起來更有效率,即使是對同時使用鍵盤和指向裝置的人來說也是如此。

快捷鍵是一種鍵盤組合,透過為使用者提供存取應用程式功能的有效方法來提高工作效率。 快捷鍵有兩種:

  • 存取按鍵是前往應用程式中特定 UI 的捷徑。 存取按鍵是由 Alt 鍵加上字母鍵所組成。
  • 快速鍵是存取應用程式命令的捷徑。 應用程式不見得會有與特定命令完全對應的 UI。 快速鍵是由 Ctrl 鍵加上字母鍵所組成。

您必須為仰賴螢幕助讀程式和其他輔助技術的使用者提供一種簡單的機制,幫助他們發現您的應用程式所提供的快捷鍵。 您可以透過工具提示、可存取名稱、可存取描述或其他形式的螢幕通訊方式,來傳達快捷鍵。 請至少在應用程式的 [說明] 內容中清楚記錄快捷鍵。

您可以將 AutomationProperties.AccessKey 附加屬性設定為一個用來描述快捷鍵的字串,以透過螢幕助讀程式記錄存取按鍵。 還有一個 AutomationProperties.AcceleratorKey 附加屬性可用於記錄非助憶快捷鍵,儘管螢幕助讀程序通常會以相同的方式處理這兩個屬性。 請嘗試以多種方式記錄快捷鍵,包括工具提示、自動化屬性和書面說明文件。

下列範例示範如何記錄媒體播放、暫停和停止按鈕的快捷鍵。

XAML

<Grid KeyDown="Grid_KeyDown">

  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>

  <MediaElement x:Name="DemoMovie" Source="xbox.wmv"
    Width="500" Height="500" Margin="20" HorizontalAlignment="Center" />

  <StackPanel Grid.Row="1" Margin="10"
    Orientation="Horizontal" HorizontalAlignment="Center">

    <Button x:Name="PlayButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+P"
      AutomationProperties.AcceleratorKey="Control P">
      <TextBlock>Play</TextBlock>
    </Button>

    <Button x:Name="PauseButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+A"
      AutomationProperties.AcceleratorKey="Control A">
      <TextBlock>Pause</TextBlock>
    </Button>

    <Button x:Name="StopButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+S"
      AutomationProperties.AcceleratorKey="Control S">
      <TextBlock>Stop</TextBlock>
    </Button>
  </StackPanel>
</Grid>

重要

設定 AutomationProperties.AcceleratorKeyAutomationProperties.AccessKey 不會啟用鍵盤功能。 這麼做只會向 UI 自動化架構回報應該使用哪些按鍵,以便透過輔助技術將這些資訊傳遞給使用者。 您仍然需要在程式碼 (而非 XAML) 中完成按鍵處理的實作。 您仍然需要在相關控制項上附加 KeyDownKeyUp 事件的處理常式,才能在應用程式中實際實作鍵盤快速鍵行為。 此外,不會自動為存取按鍵提供下底線的文字效果。 如果您希望在 UI 中顯示標有下底線的文字,則必須明確對助憶鍵中特定鍵的文字標註下底線,作為內嵌 Underline 格式。

為了簡單起見,上面的範例省略了字串資源的使用,例如「Ctrl+A」。 不過,在當地語系化期間也必須考慮快捷鍵。 快捷鍵的當地語系化之所以重要,是因為要選擇哪個鍵做為快捷鍵,通常取決於元素的可見文字標籤。

如需有關實作快捷鍵的進一步指引,請參閱 Windows User Experience Interaction Guidelines (Windows 使用者經驗指導方針) 中的快捷鍵

實作按鍵事件處理常式

輸入事件 (例如按鍵事件) 會使用稱為路由事件的概念。 路由事件可以透過複合控制項的子元素反昇,讓常見的控制項父代可以處理多個子元素的事件。 當控制項包含多個複合部分,而這些部分在設計上不能獲得焦點、或成為定位順序的一部分時,此事件模型可以很方便地定義這類控制項的快捷鍵動作。

您可以在撰寫按鍵事件處理常式時,加入用來檢查 Ctrl 鍵等輔助按鍵的功能;如需範例程式碼,請參閱鍵盤互動

使用鍵盤導覽自訂控制項

當子元素彼此之間存在間隔時,建議使用方向鍵做為在子元素之間導覽的鍵盤快速鍵。 如果樹狀結構檢視使用個別的子元素來處理展開/收合和節點啟用,請使用向左鍵和向右鍵提供鍵盤展開/收合功能。 如果您有一個定向控制項支援在控制項内容中定向周遊,請使用對應的方向鍵。

通常,您可以透過覆寫類別邏輯中的一部分 OnKeyDownOnKeyUp 方法,來實作自訂控制項的自訂按鍵處理。

焦點指標的視覺狀態範例

我們之前提到過,任何可讓使用者設為焦點的自訂控制項,都應該有一個視覺焦點指標。 這類焦點指標通常十分簡單,例如在控制項的正常週框矩形周圍繪製一個矩形。 用來當做視覺焦點的 Rectangle 是控制項範本中其餘控制項組成部分的對等元素,但一開始會將 Visibility 值設定為 Collapsed,因為控制項尚未獲得焦點。 接著,當控制項獲得焦點時,就會叫用視覺狀態,將焦點視覺效果的 Visibility 設定為 Visible。 一旦將焦點移動至別處,就會呼叫另一個視覺狀態,而 Visibility 會變成 Collapsed

所有預設的 XAML 控制項在獲得焦點時,都會顯示適當的視覺焦點指標 (如果可以獲得焦點的話)。 此外,根據使用者選擇的主題 (特別是使用高對比模式時),還可能顯示不同的外觀。如果您在 UI 中使用 XAML 控制項,而不是取代控制項範本,則您不需要執行任何額外的動作,就可以在控制項上取得視覺焦點指標,並正確地執行和顯示。 但是,如果您想要重新範本化控制項,或想知道 XAML 控制項如何提供視覺焦點指標,本節其餘部分將說明如何在 XAML 和控制邏輯中完成此操作。

以下是一些來自 Button 之預設 XAML 範本的範例 XAML。

XAML

<ControlTemplate TargetType="Button">
...
    <Rectangle
      x:Name="FocusVisualWhite"
      IsHitTestVisible="False"
      Stroke="{ThemeResource FocusVisualWhiteStrokeThemeBrush}"
      StrokeEndLineCap="Square"
      StrokeDashArray="1,1"
      Opacity="0"
      StrokeDashOffset="1.5"/>
    <Rectangle
      x:Name="FocusVisualBlack"
      IsHitTestVisible="False"
      Stroke="{ThemeResource FocusVisualBlackStrokeThemeBrush}"
      StrokeEndLineCap="Square"
      StrokeDashArray="1,1"
      Opacity="0"
      StrokeDashOffset="0.5"/>
...
</ControlTemplate>

目前仍僅處於組合階段。 若要控制焦點指標的可見性,您可以定義用來切換 Visibility 屬性的視覺狀態。 這需要使用 VisualStateManager 和 VisualStateManager.VisualStateGroups 附加屬性,並套用至用於定義組合的根元素。

XAML

<ControlTemplate TargetType="Button">
  <Grid>
    <VisualStateManager.VisualStateGroups>
       <!--other visual state groups here-->
       <VisualStateGroup x:Name="FocusStates">
         <VisualState x:Name="Focused">
           <Storyboard>
             <DoubleAnimation
               Storyboard.TargetName="FocusVisualWhite"
               Storyboard.TargetProperty="Opacity"
               To="1" Duration="0"/>
             <DoubleAnimation
               Storyboard.TargetName="FocusVisualBlack"
               Storyboard.TargetProperty="Opacity"
               To="1" Duration="0"/>
         </VisualState>
         <VisualState x:Name="Unfocused" />
         <VisualState x:Name="PointerFocused" />
       </VisualStateGroup>
     <VisualStateManager.VisualStateGroups>
<!--composition is here-->
   </Grid>
</ControlTemplate>

請注意,只有其中一個具名狀態會直接調整 Visibility,而其他狀態則似乎為空白。 視覺狀態的運作方式是,只要控制項使用來自相同 VisualStateGroup 的另一個狀態,就會立即取消先前狀態所套用的任何動畫。 由於組合的預設 VisibilityCollapsed,因此不會顯示矩形。 控制邏輯進行控制的方法包括接聽 GotFocus 等焦點事件,以及使用 GoToState 來變更狀態。 如果您使用預設控制項、或基於已具有該行為的控制項進行自訂,通常這已為您處理完成。

鍵盤協助工具和 Windows Phone

Windows Phone 裝置通常沒有專用的硬體鍵盤。 但是,螢幕輸入面板 (SIP) 可支援多種鍵盤協助工具場景。 螢幕助讀程式可以從 Text SIP 讀出輸入的文字,包括刪除動作。 使用者可以得知手指的位置,因為螢幕助讀程式可以偵測到使用者正在滑過按鍵,並會大聲讀出滑過的按鍵名稱。 此外,有些以鍵盤為導向的無障礙概念可以對應至完全不使用鍵盤的相關輔助技術行為。 例如,即使 SIP 不包含 Tab 鍵,朗讀程式仍支援相當於按下 Tab 鍵的觸控手勢,因此為 UI 中的控制項提供有用的定位順序,仍是一項重要的協助工具原則。 此外,也可以使用朗讀程式觸控手勢,支援使用方向鍵導覽複雜控制項內各個部分的功能。 當焦點到達不是用來輸入文字的控制項時,朗讀程式就會支援呼叫該控制項動作的手勢。

鍵盤快速鍵通常與 Windows Phone 應用程式無關,因為 SIP 不包含 Control 或 Alt 鍵。

範例

提示

WinUI 3 資源庫應用程式內含大多數 WinUI 3 控制項和功能的互動式範例。 從 Microsoft Store 取得應用程式,或在 GitHub 上取得原始程式碼