Delen via


Toetsenbordtoegankelijkheid

Toetsenbordtoegankelijkheid moet worden behandeld als een primair interactiemodel, niet als een secundaire terugval. Een robuuste toetsenbordervaring biedt ondersteuning voor gebruikers met verschillende beperkingen (waaronder gezichtsvermogen, leren, mobiliteit en taal-/communicatieproblemen). Het verbetert ook de productiviteit voor gebruikers die de voorkeur geven aan interactie met het toetsenbord voor snelheid en precisie.

Als toetsenbordtoegang onvolledig of inconsistent is, kunnen gebruikers de toegang tot de kernfunctionaliteit van de app verliezen, zelfs wanneer de interactie met aanwijzers volledig wordt geïmplementeerd.

Toetsenbordnavigatie tussen UI-elementen

Om te communiceren met een besturingselement via het toetsenbord, moeten besturingselementen focusbaar en bereikbaar zijn via focusverplaatsing. Als u de focus wilt ontvangen (zonder een aanwijzer te gebruiken), moet het besturingselement toegankelijk zijn via tabnavigatie. Als standaardinstelling is de tabvolgorde van besturingselementen hetzelfde als de volgorde waarin ze worden toegevoegd aan een ontwerpvlak, gedeclareerd in XAML, of programmatisch worden toegevoegd aan een container.

In veel UIS's is dit standaardgedrag acceptabel en komt overeen met de leesstroom. De visuele volgorde en de toetsenbordvolgorde kunnen echter afwijken, afhankelijk van de containerindeling en de positionering van de elementen. Deze afwijking moet opzettelijk zijn en worden getest.

Tabgedrag expliciet valideren. Raster-, tabel- en vergelijkbare indelingen zijn vaak bronnen van discrepanties tussen de waargenomen leesvolgorde en de focusvolgorde. Test zowel de toetsenbord- als aanraakinteractiewijzen om ervoor te zorgen dat de navigatie efficiënt en voorspelbaar blijft.

Als u de navigatie wilt afstemmen op de visuele stroom, kunt u XAML opnieuw structureren of TabIndex expliciet toewijzen. In het volgende voorbeeld wordt een raster met kolom-first tabvolgorde gebruikt.

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

In sommige scenario's moet een element worden uitgesloten van tab-navigatie. De standaardmethode is het instellen van IsEnabled op false, waardoor ook interactie wordt uitgeschakeld. Gedeactiveerde besturingselementen worden automatisch verwijderd uit de tabvolgorde.

Als een element interactief blijft via andere mechanismen, maar niet mag worden bereikt met Tab, stelt u IsTabStop in op false.

De meeste besturingselementen die geschikt zijn voor focus, zijn standaard opgenomen in de tabvolgorde. Een veelvoorkomende uitzondering is besturingselementen voor tekstweergave, zoals RichTextBlock, die de focus kunnen ondersteunen voor tekstselectie- en klembordbewerkingen, maar meestal niet tabstops zijn omdat het geen besturingselementen voor opdrachten zijn. Deze besturingselementen kunnen nog steeds worden gedetecteerd door ondersteunende technologieën via automatiseringssemantiek, zoals het Tekstbeheerpatroon.

Of u nu standaard doorkruising of expliciete TabIndex gebruikt, de volgende regels zijn van toepassing:

  • Als TabIndex niet is ingesteld op een element, is de standaardwaarde Int32.MaxValue en de volgorde is gebaseerd op declaratie/invoegvolgorde.
  • Als TabIndex is ingesteld op een element:
    • Elementen met TabIndex gelijk aan 0 worden toegevoegd op basis van de declaratie-/invoegvolgorde.
    • Elementen met TabIndex groter dan 0 worden toegevoegd in oplopende TabIndex-volgorde .
    • Elementen met TabIndex kleiner dan 0 worden toegevoegd voordat elementen met nulwaarden worden toegevoegd.

In het volgende fragment ziet u gemengde TabIndex-instellingen (B gebruikt Int32.MaxValue of 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>

Dit produceert de volgende tabvolgorde:

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

Toetsenbordnavigatie tussen toepassingsvensters met F6

Een toepassingsvenster is een prominent taakgebied in een venster. In Microsoft Edge bevatten deelvensters bijvoorbeeld de adresbalk, bladwijzerbalk, tabstrook en inhoudsgebied. F6 wordt vaak gebruikt om de focus tussen deze deelvensters te verplaatsen, waarbij kindelementen toegankelijk zijn via standaard toetsenbordnavigatie.

Hoewel een compatibel toetsenbordnavigatiemodel de basislijn is, omvat een bruikbaar toetsenbordnavigatiemodel meestal ook:

  • Luisteren naar F6 om te schakelen tussen belangrijke UI-regio's.
  • Sneltoetsen bieden voor opdrachten met een hoge frequentie.
  • Toegangssleutels bieden voor belangrijke bedieningselementen.

Zie sneltoetsen en toegangstoetsen voor implementatierichtlijnen.

Optimaliseren voor F6

F6 vermindert de doorkruisingskosten aanzienlijk door gebruikers te laten springen tussen hoofdzones in plaats van door elk subbesturingselement te bladeren.

F6 schakelt in Microsoft Edge bijvoorbeeld tussen de adresbalk, bladwijzerbalk, tabstrook en inhoud. Omdat een pagina veel tabstops kan bevatten, worden algemene navigatietaken veel efficiënter.

De F6-reeks kan worden uitgelijnd met oriëntatiepunten of koppen, maar hoeft niet exact overeen te komen. Gebruik F6 voor algemene bewegingen en oriëntatiepunten/koppen op regioniveau voor semantische structuur binnen en tussen regio's.

Belangrijk

U moet F6-navigatie expliciet implementeren in uw app; deze wordt niet automatisch verstrekt.

Waar mogelijk moet elke F6-doelregio een duidelijke toegankelijke naam hebben, hetzij vanuit de semantiek van landmarks of door AutomationProperties.Name in te stellen op de root van de regio.

Shift+F6 moet dezelfde cyclus in omgekeerde volgorde doorlopen.

Toetsenbordnavigatie in een UI-element

Samengestelde besturingselementen moeten voorspelbare binnennavigatie bieden tussen onderliggende elementen. Een veelvoorkomend patroon is om de samengestelde hoofdmap intern te houden en actieve afstammelingen intern te beheren, in plaats van elk kind als afzonderlijke tabstop weer te geven.

Veel ingebouwde besturingselementen implementeren dit gedrag al. Het doorkruisen met de pijltoets is bijvoorbeeld standaard beschikbaar voor ListView, GridView, ListBox en FlipView.

Toetsenbordalternatieven voor aanwijzeracties en -gebeurtenissen voor specifieke besturingselementen

Elke gebruikersinterface die met aanwijzer kan worden geactiveerd, moet ook via het toetsenbord kunnen worden aangestuurd. Voor activering moet het element focus hebben (alleen klassen die zijn afgeleid van Control ondersteunen focus en tabnavigatie).

Voor besturingselementen die kunnen worden aangeroepen, implementeert u handlers voor toetsenbordgebeurtenissen voor de spatiebalk en Enter-toetsen. Dit biedt eenvoudige toetsenbordpariteit met aanwijzerinteracties.

Als een element standaard niet geschikt is voor focus, gebruikt u een focusbaar besturingselementtype of implementeert u een aangepast besturingselement met expliciet focusgedrag. In dat geval stelt u IsTabStop in op true en geeft u een zichtbare focusindicator op.

In veel gevallen is samenstelling eenvoudiger en robuuster dan aangepast gedrag met alleen aanwijzers. In plaats van invoer van aanwijzer rechtstreeks op een afbeelding te verwerken, plaatst u deze bijvoorbeeld in een knop om toetsenbordactivering, focusafhandeling en automatiseringsgedrag over te nemen.

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

<!--Do this instead.-->
<Button Click="Button_Click"
        AutomationProperties.Name="Open profile photo">
  <Image Source="Assets/profile-photo.png"/>
</Button>

Sneltoetsen op het toetsenbord

Naast navigatie en activering implementeert u een sneltoets (een toetsencombinatie die efficiënte toegang biedt tot app-functionaliteit) voor belangrijke of veelgebruikte opdrachten met toetsenbordversnellers en toegangstoetsen.

Twee veelvoorkomende typen snelkoppelingen zijn:

  • Accelerators: roep opdrachten rechtstreeks aan, met of zonder een bijbehorend zichtbaar besturingselement.
  • Toegangssleutels: verplaats de focus naar specifieke besturingselementen in uw gebruikersinterface.

Maak snelkoppelingen altijd detecteerbaar voor gebruikers van ondersteunende technologie. Communiceer ze via tooltips, automatiseringsmetadata, zichtbare UI-elementen en helpdocumentatie.

Als u snelkoppelingsmetagegevens beschikbaar wilt maken voor ondersteunende technologieën, gebruikt u AutomationProperties.AccessKey voor mnemonic-snelkoppelingen en AutomationProperties.AcceleratorKey voor opdrachtsnelkoppelingen. Omdat schermlezers deze op een vergelijkbare manier kunnen presenteren, documenteer snelkoppelingen in meerdere kanalen.

In het volgende voorbeeld ziet u hoe u sneltoetsen voor media afspelen, onderbreken en stoppen kunt documenteren.

<Grid>

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

  <MediaPlayerElement x:Name="DemoPlayer"
    Width="500" Height="300" Margin="20"
    HorizontalAlignment="Center"
    AutoPlay="False"
    AreTransportControlsEnabled="True" />

  <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="Ctrl+P"
      AutomationProperties.AccessKey="Alt+P">
      <Button.KeyboardAccelerators>
        <KeyboardAccelerator Modifiers="Control" Key="P"/>
      </Button.KeyboardAccelerators>
      <TextBlock>Play</TextBlock>
    </Button>

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

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

Belangrijk

Het instellen van AutomationProperties.AcceleratorKey of AutomationProperties.AccessKey implementeert geen toetsenbordgedrag. Deze eigenschappen maken metagegevens beschikbaar voor UI Automation, zodat ondersteunende technologieën de verwachte snelkoppelingen kunnen aankondigen.

Toetsenbordgedrag moet nog steeds worden geïmplementeerd in code. Gebruik indien mogelijk declaratieve KeyboardAccelerator-definities en gebruik KeyDown - of KeyUp-handlers waarvoor u aangepaste routeringslogica nodig hebt. Houd er ook rekening mee dat de onderstrepingsstijl van de toegangssleutel niet automatisch is. Als u zichtbare mnemonische onderstrepingen wilt, geeft u deze expliciet weer (bijvoorbeeld met Onderstrepen).

Kortom, in het voorbeeld worden tekenreeksbronnen weggelaten, zoals Ctrl+A. Lokaliseer in de productieomgeving de tekst van snelkoppelingen en valideer mnemonic-keuzes per locale, omdat de sleutelselectie vaak afhankelijk is van vertaalde labels.

Zie sneltoetsen in de richtlijnen voor interactie met Windows-gebruikerservaring voor aanvullende richtlijnen.

Een sleutel-gebeurtenis-handler implementeren

Sleutelinvoer maakt gebruik van gerouteerde gebeurtenissen. Gerouteerde gebeurtenissen kunnen van onderliggende elementen naar een bovenliggende container propageren, waardoor de bovenliggende container snelkoppelingen voor meerdere onderliggende elementen kan verwerken. Dit gebeurtenismodel is handig voor het definiëren van sneltoetsacties voor een besturingselement dat verschillende onderliggende elementen bevat, waarvan geen enkele focus kan hebben of deel kan uitmaken van de tabvolgorde.

Zie Toetsenbordinteracties voor codevoorbeelden met modifier-toetscontroles (bijvoorbeeld Ctrl).

Toetsenbordnavigatie voor aangepaste bedieningselementen

Gebruik voor aangepaste besturingselementen pijltoetsen wanneer onderliggende elementen ruimtelijk zijn gerelateerd. In structuurscenario's waarbij uitvouwen/samenvouwen en activeren afzonderlijke interacties zijn, worden de pijl-links en pijl-rechts toegewezen om uitvouwen/samenvouwen gedrag aan te sturen. Voor gerichte bedieningselementen wijst u richtingtoetsen toe aan de visuele oriëntatie van het bedieningselement.

Aangepast sleutelgedrag wordt meestal geïmplementeerd door OnKeyDown en OnKeyUp te overschrijven.

Een voorbeeld van een visuele status voor een focusindicator

Elk focusbaar aangepast besturingselement moet een duidelijke visuele focusindicator weergeven. Een algemeen sjabloonpatroon maakt gebruik van een rechthoek-overlay die wordt verborgen via Zichtbaarheid en wordt weergegeven wanneer de focus wordt ingevoerd.

Ingebouwde XAML-besturingselementen bieden al focusindicatoren. Het exacte uiterlijk kan variëren met thema-instellingen, waaronder de modus hoog contrast. Als u besturingselementen opnieuw vertemplatet, behoudt u het equivalente zichtbaarheidsgedrag van de focus.

Het volgende voorbeeld is aangepast aan de standaardknopsjabloon .

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

Als u de zichtbaarheid van focusindicatoren wilt in- of uitschakelen, gebruikt u VisualStateManager en VisualStateManager.VisualStateGroups in de hoofdmap van de sjabloon.

<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"/>
          </Storyboard>
        </VisualState>
        <VisualState x:Name="Unfocused" />
        <VisualState x:Name="PointerFocused" />
      </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <!--composition is here-->
  </Grid>
</ControlTemplate>

Slechts één staat in deze groep wijzigt expliciet de focusweergave. De andere statussen kunnen leeg blijven omdat overgangen binnen dezelfde VisualStateGroup eerdere statusanimaties annuleren. Focusevenementen zoals GotFocus, gecombineerd met GoToState, sturen deze overgangen doorgaans aan.

Toetsenbordtoegankelijkheid en apparaten zonder hardwaretoetsenbord

Sommige apparaten zijn afhankelijk van een SIP (Soft Input Panel) in plaats van een hardwaretoetsenbord. Schermlezers kunnen detecteren dat de gebruiker toetsen scant en de SIP-sleutelverkenning van een gebruiker aankondigt, en veel concepten voor toegankelijkheid van toetsenborden zijn nog steeds van toepassing via gebarenequivalenten.

Verteller ondersteunt bijvoorbeeld gebaren die worden gebruikt voor navigatie, vergelijkbaar met de Tab-toets, zelfs zonder een fysieke Tab-toets. Dat betekent dat coherente tabvolgorde nog steeds kritiek is. Verteller biedt ook gebarenequivalenten voor navigatie in complexe besturingselementen (zie Toetsenbordopdrachten van Verteller en aanraakbewegingen).

Voorbeelden

Pictogram WinUI 3-galerie De WinUI 3 Gallery-app bevat interactieve voorbeelden van WinUI-besturingselementen en -functies. Haal de app op uit de Microsoft Store of blader door de broncode op GitHub.