Barrierefreie Softwareentwicklung mit C# und WPF nach EN 301 549 und WCAG 2.2 – Anleitung 2024

In diesem Blogartikel erkläre ich die barrierefreie Softwareentwicklung mit der Programmiersprache C# und dem  Framework WPF, das die plattformunabhängige Entwicklung von Anwendungen unterstützt.

Betriebssystem, Entwicklungsumgebung, Programmiersprache, Framework

Softwareumgebung Im Einsatz
Betriebssystem Windows 11
Entwicklungsumgebung Visual Studio 2022
Programmiersprache C#
Framework WPF

Barrierefreie Softwareentwicklung mit C# WPF: Was erwartet Sie in diesem Artikel?

In diesem Blogartikel erfahren Sie, wie Sie barrierefreie Softwarelösungen mithilfe von C# WPF (Windows Presentation Foundation) entwickeln können. Als Experte teile ich wertvolle Tipps und Techniken mit Ihnen, um sicherzustellen, dass Ihre Anwendungen für alle Benutzer zugänglich und nutzbar sind. Entdecken Sie bewährte Praktiken für barrierefreie Softwareentwicklung und erfahren Sie, wie C# WPF Ihnen dabei helfen kann, die Benutzererfahrung für alle zu verbessern. Starten Sie jetzt und gestalten Sie Ihre Anwendungen inklusiver!

Barrierefreie Softwareentwicklung – Eine Einführung

Barrierefreie Softwareentwicklung bedeutet, dass Software so gestaltet wird, dass sie von allen Menschen genutzt werden kann, unabhängig von etwaigen Behinderungen oder körperlichen Einschränkungen. In diesem Blogartikel geht es um barrierefreie Softwareentwicklung mit der Programmiersprache C# und der Windows Presentation Foundation (WPF).

Wichtige Fakten zur Programmiersprache C#

C# (C-Sharp) ist eine moderne und vielseitige Programmiersprache, die von Microsoft entwickelt wurde. Hier sind einige wichtige Fakten zur Programmiersprache C#, leicht verständlich erklärt:

Entwicklungsumgebung: C# wird typischerweise mit der Entwicklungsumgebung Visual Studio von Microsoft entwickelt. Visual Studio bietet eine umfangreiche Integration von Tools und Funktionen, die die Entwicklung in C# erleichtern.

Typsicherheit und strenge Syntax: C# ist eine typsichere Sprache, was bedeutet, dass Variablen und Datentypen zur Kompilierzeit überprüft werden, um Fehler zu vermeiden. Die Sprache verwendet eine strenge Syntax, was die Lesbarkeit und Wartbarkeit des Codes verbessert.

Objektorientierte Programmierung: C# ist stark objektorientiert und unterstützt Konzepte wie Klassen, Vererbung, Schnittstellen, und Polymorphismus. Dies fördert eine modulare und strukturierte Entwicklung von Anwendungen.

Plattformunabhängigkeit: C# kann mit der .NET-Plattform entwickelt werden, die die Entwicklung plattformunabhängiger Anwendungen ermöglicht. Mit .NET Core und dem neueren .NET 5 und .NET 6 sind plattformübergreifende Entwicklung und Unterstützung für verschiedene Betriebssysteme wie Windows, macOS und Linux möglich.

Verwendungsbereiche: C# wird häufig für die Entwicklung von Desktopanwendungen (z.B. mit WPF), Webanwendungen (z.B. mit ASP.NET), Spieleentwicklung (mit Unity), Datenbankanwendungen, Dienstprogrammen und vielem mehr eingesetzt.

Integrierte Sicherheit: C# bietet integrierte Sicherheitsfunktionen wie Garbage Collection zur Speicherverwaltung und verhindert bestimmte Arten von Fehlern wie Pufferüberlauf.

Wachsende Community und Ressourcen: C# hat eine wachsende Entwickler-Community und umfangreiche Ressourcen, einschließlich Tutorials, Online-Kurse, Foren und Bibliotheken, die die Entwicklung erleichtern und beschleunigen.

C# ist eine leistungsstarke und fortschrittliche Sprache, die sowohl für Anfänger als auch für erfahrene Entwickler geeignet ist. Sie bietet eine breite Palette von Anwendungsmöglichkeiten und ist eine der beliebtesten Programmiersprachen für die Entwicklung von Anwendungen im Microsoft-Ökosystem.

Wichtige Fakten zum Framework WPF

WPF (Windows Presentation Foundation) ist ein Framework von Microsoft zur Entwicklung grafischer Benutzeroberflächen für Windows-Anwendungen.

WPF ermöglicht die Erstellung moderner und ansprechender Benutzeroberflächen durch die Verwendung von XAML (eXtensible Application Markup Language) zur Beschreibung der Benutzeroberfläche und der Verwendung von .NET-Programmierung für die Logik. Mit WPF können Entwickler interaktive und visuell ansprechende Anwendungen erstellen, die 2D- und 3D-Grafiken, Animationen, Datenbindung, Vorlagen und viele andere Funktionen unterstützen.

WPF basiert auf einer leistungsstarken Architektur, die die Trennung von Design und Logik ermöglicht. Dadurch können Entwickler effizient arbeiten und die Benutzeroberfläche unabhängig von der Anwendungslogik gestalten. WPF bietet zudem eine Vielzahl von Steuerelementen und Stilen, die es einfach machen, eine konsistente und ansprechende Benutzererfahrung zu schaffen.

Was Programmieren wir?

Wir programmieren eine Eingabemaske, in die der Anwender folgende Daten eingeben kann:

  • Vorname
  • Nachname
  • Strasse
  • Postleitzahl
  • Ort
  • Telefonnummer
  • E-Mailadresse
Eingabemaske für Postaanschrift, Telefonnummer und Mailadresse einer Person programmiert mit der Programmiersprache C# und dem Grafik-Framework WPF
Eingabemaske für Postanschrift, Telefonnummer und Mailadresse einer Person programmiert mit der Programmiersprache C# und dem Grafik-Framework WPF

Nach welchen Richtlinien programmieren wir barrierefrei?

Was sind Richtlinien für barrierefreie Programmierung? Damit eine Software, egal mit welcher Programmiersprache sie entwickelt wird, barrierefrei programmiert werden kann, bedarf es Richtlinien. Die Richtlinien sorgen dafür, dass Menschen mit unterschiedlichen Behinderungen oder anderen körperlichen Einschränkungen eine Software bedienen können. Wenn eine Software für ein europäisches Land barrierefrei programmiert wird, sollte die Richtlinie EN 301 549 verwendet werden. Hier ein Link zu den Prüfschritten der EN 301 549: BITV-Test / EN 301 549 (Web)Prüfschritte Wenn eine Software für ein nicht europäisches Land barrierefrei programmiert werden soll, sollte die Richtlinie WCAG 2.2 verwendet werden. Hier ein Link zu den Prüfschritten der WCAG 2.2: Web Content Accessibility Guidelines (WCAG) 2.2 Weil die EN 301 549 Menschen mit bestimmten körperlichen Beeinträchtigungen ausschließt, verwenden wir beide Richtlinien für unsere barrierefreie C#-Software.

Barrierefreie Softwareentwicklung mit C# und WPF – einzelne Prüfschritte im Code umgesetzt

In diesem Abschnitt finden Sie die einzelnen Schritte zur Barrierefreie Softwareentwicklung mit C# und WPF. Wenn Sie statt Text lesen lieber ein Video schauen, dann gibt es hier ein Video:

Screenreadertauglichkeit

Die Screenreadertauglichkeit wird explizit in der EN 301 549 nicht erwähnt, Sie ist aber wichtig, damit blinde Menschen eine C# WPF-Anwendung bedienen können.

Die C# WPF Bedienoberfläche muss texte enthalten die beschreiben, was auf der Oberfläche zu sehen ist. Diese Texte werden dann von einem Screenreader vorgelesen. Den Eingabefeldern und dem Button werden solche Texte hinterlegt mit AutomationProperties.HelpText.

Der gesamte XAML-Code den ich in diesem Blogartikel veröffentliche ist bei mir in der Datei „MainWindow.xaml“.

XAML-Code:

AutomationProperties.HelpText="Schriftgröße in ganzer Anwendung vergrößern" AutomationProperties.HelpText="Bitte geben Sie eine Vornamen ein!"

Tastaturbedienbarkeit

Für eine barrierefreie Bedienung von C# WPF-Anwendungen durch blinde und sehbehinderte Menschen ist es wichtig, dass alle Bedienelemente mithilfe der Tastatur erreichbar sind. Diese Anforderung ist gemäß Prüfschritt 9.2.1.1 „Ohne Maus nutzbar“ der EN 301 549 festgelegt.

Um sicherzustellen, dass Benutzer die Bedienelemente mit der Tabulatortaste erreichen können, sind keine zusätzlichen Programmierungen erforderlich. Eine weitere Verbesserung der Tastaturbedienbarkeit kann durch die Nutzung von Tastenkombinationen für Eingabefelder erreicht werden. Hierzu werden die Labels mit den entsprechenden Eingabefeldern verknüpft. Die Textbox benötigt hierzu das Attribut x:Name=“edtVorname“, damit die Verknüpfung funktioniert.

Im Label wird mit dem Target-Attribut und Binding das Label mit der Textbox verknüpft.

XAML-Code:

<label Grid.Row="0" Grid.Column="0" FontSize="{Binding FontSize}" FocusVisualStyle="{DynamicResource MyFocusVisual}" Target="{Binding ElementName=edtVorname}">
<textbox x:Name="edtVorname" Grid.Row="0" Grid.Column="1" FontSize="{Binding FontSize}" FocusVisualStyle="{DynamicResource MyFocusVisual}" Height="56" AutomationProperties.HelpText="Bitte geben Sie einen Vornamen ein!">
</textbox></label></textbox></label>

Damit das Label per Tastenkürzel aktivierbar ist, muss ein Tastenkürzel festgelegt werden. Dies geschieht mit . Vor dem Buchstaben, der das Tastenkürzel sein soll, schreibt man einen Unterstrich (_).

XAML-Code:

<AccessText Text="_Textgröße"/>

Aktuelle Position des Fokus deutlich

EN 301 549 Prüfschritt 9.2.4.7 Aktuelle Position des Fokus deutlich.

Für Menschen mit Sehbehinderungen ist es wichtig zu wissen, welches Bedienelement gerade den Fokus hat. Das aktive Bedienelement wird visuell hervorgehoben, indem es eine gelbe Hintergrundfarbe erhält. Um dies zu erreichen, wurden zunächst in den Window.Resources Ressourcen definiert, die eine gelbe Hintergrundfarbe für den Fokus visualisieren.

XAML-Code:

<Window.Resources>
    <solidcolorbrush x:Key="OnTextboxFocus" Color="Yellow"></solidcolorbrush>
    <style x:Key="MyFocusVisual">
        <setter Property="Control.Template">
            <Setter.Value>
                <controltemplate>
                    <rectangle Margin="-2" StrokeThickness="5" Stroke="Red" StrokeDashArray="1 2"></rectangle>
                </controltemplate>
            </Setter.Value>
        </setter>
    </style>
</Window.Resources>

Anschließend wurde in den Stilen der einzelnen TextBoxen und Buttons ein Trigger verwendet, der die Hintergrundfarbe auf Gelb ändert, wenn das Element den Fokus erhält.

XAML-Code:

<TextBox.Style>
    <style TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <trigger Property="IsFocused" Value="true">
                <setter Property="Background" Value="{StaticResource OnTextboxFocus}"></setter>
            </trigger>
        </Style.Triggers>
    </style>
</TextBox.Style>

Wenn ja, wird die Hintergrundfarbe auf Gelb gesetzt, indem der Wert von Background auf die definierte Ressource OnTextboxFocus gesetzt wird. Gleiches gilt für Schaltflächen.

XAML-Code:

<Button.Style>
    <style TargetType="{x:Type Button}">
        <Style.Triggers>
            <trigger Property="IsFocused" Value="true">
                <setter Property="Background" Value="{StaticResource OnTextboxFocus}"></setter>
            </trigger>
        </Style.Triggers>
    </style>
</Button.Style>

Dieser Trigger muss für jede TextBox und jeden Button festgelegt werden, um die visuelle Fokushervorhebung zu gewährleisten.

Kontraste von Texten ausreichend

EN 301 549 Prüfschritt 9.1.4.3 Kontraste von Texten ausreichend. Für Menschen mit einer Farbfehlsichtigkeit ist es wichtig, dass genug Farbkontrast zwischen Schriftfarbe und Hintergrundfarbe ist.

Dies kann mit der Kostenlosen Software Colour Contrast Analyzer (CCA) überprüft werden. Hier ein Video von mir wie der Colour Contrast Analyzer eingesetzt werden kann: In der C# WPF-Anwendung musste keine Farbanpassung gemacht werden. Die Standardfarben sind barrierefrei.

Mindestgröße für Bedienelemente

In der Richtlinie EN 301 549 fehlt dieser Prüfschritt, wodurch bestimmte Menschen ausgeschlossen werden. Hingegen ist dieser Prüfschritt in der WCAG 2.2 Success Criterion 2.5.8 Target Size (Minimum) enthalten und auch in den Google-Richtlinien „Apps barrierefrei gestalten“ unter dem Prüfschritt „Große, einfache Steuerelemente verwenden“ zu finden. Besonders für Menschen mit eingeschränkter Handfunktion, beispielsweise nach einem Schlaganfall, ist es wichtig, dass Schaltflächen eine Mindestgröße haben. Die WCAG empfehlen eine Größe von 24×24 Pixeln, während Google eine Mindesthöhe von etwa 3,5 REM (Fontgröße) empfiehlt. Diese Richtlinien setze ich bei der Entwicklung meiner barrierefreien Progressive Web Apps um, und sie haben sich in der Praxis bewährt. Hier ein Codebeispiel aus einer progressive Web App die ich programmiert habe:

CSS-Code:

#schliessenButton {
display: flex; align-items: center; /* Zentriert die Elemente vertikal */ justify-content: center; min-width: 8.0rem; height: 3.5rem; background-color: blue; color: #FFF; font-size: inherit; }

In dieser C# WPF-Anwendung haben die Bedienelemente eine Höhe von Height=“56″ was den 3.0rem entspricht.

XAML-Code:

<Button.Style>
    <style TargetType="{x:Type Button}">
        <Style.Triggers>
            <trigger Property="IsFocused" Value="true">
                <setter Property="Background" Value="{StaticResource OnTextboxFocus}"></setter>
            </trigger>
        </Style.Triggers>
    </style>
</Button.Style>

Text auf 200% vergrößerbar + Benutzerdefinierte Einstellungen

Prüfschritt 9.1.4.4 Text auf 200% vergrößerbar + Prüfschritt 11.7 Benutzerdefinierte Einstellungen Menschen mit einer Sehbehinderung passen häufig die Schriftgröße auf ihrem Betriebssystem an, um Texte besser lesen zu können. Diese Einstellungen werden in der C# WPF-Anwendung jedoch nicht automatisch übernommen. Daher wurden zwei Schalter (+ und -) implementiert, mit denen Benutzer die Schriftgröße innerhalb der Anwendung anpassen können. – Der Schalter mit dem Pluszeichen (+) erhöht die Schriftgröße um einen festgelegten Betrag. – Der Schalter mit dem Minuszeichen (-) verringert die Schriftgröße entsprechend. Diese Schalter ändern die Schriftgröße, indem sie die Eigenschaft ‚FontSize‘ des gesamten Inhalts der Anwendung dynamisch verändern. Hier ist der Codeausschnitt, der die Funktionalität dieser Schalter demonstriert:

XAML-Code:

<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<button Command="{Binding IncreaseTextSizeCommand}" FontSize="{Binding FontSize}" Width="50" Height="56">+</button>

<label FontSize="{Binding FontSize}">
    <accesstext Text="_Textgröße"></accesstext>
</label>

 Schalter zum Verringern der Schriftgröße 
<button Command="{Binding DecreaseTextSizeCommand}" FontSize="{Binding FontSize}" Width="50" Height="56">-</button>

Der ‚IncreaseTextSizeCommand‘ führt eine Methode aus, die die Schriftgröße um einen bestimmten Wert erhöht, während der ‚DecreaseTextSizeCommand‘ die Schriftgröße verringert. Diese Befehle sind in der ViewModel-Klasse implementiert und lösen jeweils die entsprechenden Methoden aus, um die Schriftgröße anzupassen.

C# -Code: Der folgende C#-Code ist be mir in der Datei „MainWindowViewModel.cs“.

namespace WpfApp4
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        private int _fontSize = 14;

        public MainWindowViewModel()
        {
            IncreaseTextSizeCommand = new RelayCommand(IncreaseTextSize);
            DecreaseTextSizeCommand = new RelayCommand(DecreaseTextSize);
        }

        public int FontSize
        {
            get =&gt; _fontSize;
            set
            {
                if (_fontSize != value)
                {
                    _fontSize = value;
                    OnPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void IncreaseTextSize() =&gt; FontSize += 2;

        public void DecreaseTextSize() =&gt; FontSize -= 2;

        public ICommand IncreaseTextSizeCommand { get; }
        public ICommand DecreaseTextSizeCommand { get; }

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }

    public class RelayCommand : ICommand
    {
        private readonly Action _execute;

        public RelayCommand(Action execute)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        }

        public bool CanExecute(object parameter) =&gt; true;

        public void Execute(object parameter) =&gt; _execute();

        public event EventHandler CanExecuteChanged
        {
            add { }
            remove { }
        }
    }
}

Der ganze Code: XAML und C#

In diesem Abschnitt veröffentliche ich den ganzen Code der barrierefreien Software.

Der XAML-Code

Hier der XAML-Code der Datei „MainWindow.xaml“.

<Window x:Class="WpfApp4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp4"
        mc:Ignorable="d"
        Title="Barrierefreie Softwareentwicklung mit C# WPF"
        WindowState="Maximized">
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <SolidColorBrush x:Key="OnTextboxFocus" Color="Yellow" />
        <Style x:Key="MyFocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Rectangle Margin="-2" StrokeThickness="5" Stroke="Red" StrokeDashArray="1 2"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </Window.Resources>
    <StackPanel>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Button AutomationProperties.Name="Increase Font Size" Command="{Binding IncreaseTextSizeCommand}" FontSize="{Binding FontSize}" Margin="5"  Width="50" Height="56" FocusVisualStyle="{DynamicResource MyFocusVisual}" AutomationProperties.HelpText="Schriftgröße in ganzer Anwendung vergrößern">+
                <Button.Style>
                    <Style TargetType="{x:Type Button}">
                        <Style.Triggers>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>
            </Button>
            <Label FontSize="{Binding FontSize}" 
                   Margin="5" 
                   VerticalAlignment="Center"
                   FocusVisualStyle="{DynamicResource MyFocusVisual}">
                <AccessText Text="_Textgröße"/>
                <!-- AccessKey "_T" -->
            </Label>
            <TextBox FontSize="{Binding FontSize}" Text="{Binding FontSize}" 
                     VerticalAlignment="Center" 
                     Margin="5" 
                     Width="50" 
                     Height="56" 
                     FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                     VerticalContentAlignment="Center"
                     AutomationProperties.HelpText="Bitte geben Sie eine Schriftgröße ein">
                <TextBox.InputBindings>
                    <KeyBinding Key="T" Modifiers="Alt"/>
                </TextBox.InputBindings>

                <TextBox.Style>
                    <Style TargetType="{x:Type TextBox}">
                        <Style.Triggers>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>

            </TextBox>
            <Button AutomationProperties.Name="Decrease Font Size" 
                    Command="{Binding DecreaseTextSizeCommand}" 
                    FontSize="{Binding FontSize}" 
                    Margin="5" 
                    Width="50" 
                    Height="56"  
                    FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                    AutomationProperties.HelpText="Schriftgröße in ganzer Anwendung verkleinern">-
                <Button.Style>
                    <Style TargetType="{x:Type Button}">
                        <Style.Triggers>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>

            </Button>
        </StackPanel>

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto" />
                <!-- Erste Spalte, Breite * -->
                <ColumnDefinition Width="2*" />
                <!-- Zweite Spalte, Breite 2* -->
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>

            <Label Grid.Row="0" Grid.Column="0" FontSize="{Binding FontSize}" 
                   Margin="5" VerticalAlignment="Center"
                   FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                   Target="{Binding ElementName=edtVorname}">
                <AccessText Text="_Vorname"/>
                <!-- AccessKey "_V" -->
            </Label>
            <TextBox x:Name="edtVorname" Grid.Row="0" Grid.Column="1" 
                     FontSize="{Binding FontSize}" FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                     Height="56" 
                     Margin="5"
                     VerticalContentAlignment="Center"
                     AutomationProperties.HelpText="Bitte geben Sie eine Vornamen ein!">
                <TextBox.InputBindings>
                    <KeyBinding Key="V" Modifiers="Alt" />
                </TextBox.InputBindings>
                <TextBox.Style>
                    <Style TargetType="{x:Type TextBox}">
                        <Style.Triggers>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>
            </TextBox>

            <Label Grid.Row="1" Grid.Column="0" FontSize="{Binding FontSize}" 
                   Margin="5"
                   VerticalAlignment="Center"
                   FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                   Target="{Binding ElementName=edtNachname}">
                <AccessText Text="_Nachname"/>
                <!-- AccessKey "_N" -->
            </Label>
            <TextBox x:Name="edtNachname" Grid.Row="1" Grid.Column="1" 
                     FontSize="{Binding FontSize}" 
                     FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                     Height="56" 
                     Margin="5"
                     VerticalContentAlignment="Center"
                     AutomationProperties.HelpText="Bitte geben Sie einen Nachnamen ein!">
                <TextBox.InputBindings>
                    <KeyBinding Key="N" Modifiers="Alt"/>
                </TextBox.InputBindings>
                <TextBox.Style>
                    <Style TargetType="{x:Type TextBox}">
                        <Style.Triggers>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>
            </TextBox>

            <Label Grid.Row="2" Grid.Column="0" FontSize="{Binding FontSize}" 
                   Margin="5"
                   VerticalAlignment="Center"
                   FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                   Target="{Binding ElementName=edtStrasse}">
                <AccessText Text="_Straße"/>
                <!-- AccessKey "_S" -->
            </Label>
            <TextBox x:Name="edtStrasse" Grid.Row="2" Grid.Column="1" 
                     FontSize="{Binding FontSize}" 
                     FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                     Height="56" 
                     Margin="5"
                     VerticalContentAlignment="Center"
                     AutomationProperties.HelpText="Bitte geben Sie einen Straßennamen ein!">
                <TextBox.InputBindings>
                    <KeyBinding Key="S" Modifiers="Alt"/>
                </TextBox.InputBindings>

                <TextBox.Style>
                    <Style TargetType="{x:Type TextBox}">
                        <Style.Triggers>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>
            </TextBox>

            <Label Grid.Row="3" Grid.Column="0" FontSize="{Binding FontSize}" 
                   Margin="5"
                   VerticalAlignment="Center"
                   FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                   Target="{Binding ElementName=edtPLZ}">
                <AccessText Text="_PLZ"/>
                <!-- AccessKey "_P" -->
            </Label>
            <TextBox x:Name="edtPLZ" Grid.Row="3" Grid.Column="1" 
                     FontSize="{Binding FontSize}" 
                     FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                     Height="56" 
                     Margin="5"
                     VerticalContentAlignment="Center"
                     AutomationProperties.HelpText="Geben Sie eine Postleitzahl ein">
                <TextBox.InputBindings>
                    <KeyBinding Key="P" Modifiers="Alt" />
                </TextBox.InputBindings>
                <TextBox.Style>
                    <Style TargetType="{x:Type TextBox}">
                        <Style.Triggers>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>
            </TextBox>

            <Label Grid.Row="4" Grid.Column="0" FontSize="{Binding FontSize}" 
                   Margin="5"
                   VerticalAlignment="Center"
                   FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                   Target="{Binding ElementName=edtOrt}">
                <AccessText Text="_Ort"/>
                <!-- AccessKey "_O" -->
            </Label>
            <TextBox x:Name="edtOrt" Grid.Row="4" Grid.Column="1" 
                     FontSize="{Binding FontSize}" 
                     FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                     Height="56"  
                     Margin="5"
                     VerticalContentAlignment="Center"
                     AutomationProperties.HelpText="Geben Sie einen Ortsnamen ein">
                <TextBox.InputBindings>
                    <KeyBinding Key="O" Modifiers="Alt" />
                </TextBox.InputBindings>
                <TextBox.Style>
                    <Style TargetType="{x:Type TextBox}">
                        <Style.Triggers>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>
            </TextBox>

            <Label Grid.Row="5" Grid.Column="0" FontSize="{Binding FontSize}" 
                   Margin="5"
                   VerticalAlignment="Center"
                   FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                   Target="{Binding ElementName=edtTelefon}">
                <AccessText Text="_Telefon"/>
                <!-- AccessKey "_T" -->
            </Label>
            <TextBox x:Name="edtTelefon" Grid.Row="5" Grid.Column="1" 
                     FontSize="{Binding FontSize}" 
                     FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                     Height="56" 
                     Margin="5"
                     VerticalContentAlignment="Center"
                     AutomationProperties.HelpText="Geben Sie eine Telefonnumer ein">
                <TextBox.InputBindings>
                    <KeyBinding Key="L" Modifiers="Alt"/>
                </TextBox.InputBindings>
                <TextBox.Style>
                    <Style TargetType="{x:Type TextBox}">
                        <Style.Triggers>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>
            </TextBox>

            <Label Grid.Row="6" Grid.Column="0" FontSize="{Binding FontSize}" 
                   Margin="5"
                   VerticalAlignment="Center"
                   FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                   Target="{Binding ElementName=edtEmail}">
                <AccessText Text="_E-Mail"/>
                <!-- AccessKey "_E" -->
            </Label>
            <TextBox x:Name="edtEmail" Grid.Row="6" Grid.Column="1" 
                     FontSize="{Binding FontSize}" 
                     FocusVisualStyle="{DynamicResource MyFocusVisual}" 
                     Height="56"  
                     Margin="5"
                     VerticalContentAlignment="Center"
                     AutomationProperties.HelpText="Geben Sie eine E-Mailadresse">
                <TextBox.InputBindings>
                    <KeyBinding Key="E" Modifiers="Alt"/>
                </TextBox.InputBindings>
                <TextBox.Style>
                    <Style TargetType="{x:Type TextBox}">
                        <Style.Triggers>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>
            </TextBox>

        </Grid>

        <Button FontSize="{Binding FontSize}" FocusVisualStyle="{DynamicResource 
                MyFocusVisual}" 
                Height="56" 
                Width="300"
                Margin="5"
                AutomationProperties.HelpText="Inhalt des Formulars abschicken">Abschicken
            <Button.Style>
                <Style TargetType="{x:Type Button}">
                    <Style.Triggers>
                        <Trigger Property="IsFocused" Value="true">
                            <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>
        <Button  FontSize="{Binding FontSize}" FocusVisualStyle="{DynamicResource 
                 MyFocusVisual}" Command="{Binding ExitCommand}" 
                 Height="56" 
                 Width="300"
                 Margin="5"
                 AutomationProperties.HelpText="Programm beenden">Beenden
            <Button.Style>
                <Style TargetType="{x:Type Button}">
                    <Style.Triggers>
                        <Trigger Property="IsFocused" Value="true">
                            <Setter Property="Background" Value="{StaticResource OnTextboxFocus}" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>


    </StackPanel>
</Window>

Der C#-Code

Hier der C#-Code der Datei „MainWindowViewModel.cs“.

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Automation;
using System.Windows.Input;

namespace WpfApp4
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        private int _fontSize = 14;

        public MainWindowViewModel()
        {
            IncreaseTextSizeCommand = new RelayCommand(IncreaseTextSize);
            DecreaseTextSizeCommand = new RelayCommand(DecreaseTextSize);
            ExitCommand = new RelayCommand(ExitSoftware);
        }

        public int FontSize
        {
            get => _fontSize;
            set
            {
                if (_fontSize != value)
                {
                    _fontSize = value;
                    OnPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void IncreaseTextSize() => FontSize += 2;

        public void DecreaseTextSize() => FontSize -= 2;

        public void ExitSoftware()
        {
            System.Windows.Application.Current.Shutdown();
        }

        public ICommand IncreaseTextSizeCommand { get; }
        public ICommand DecreaseTextSizeCommand { get; }
        public ICommand ExitCommand { get; }

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }

    public class RelayCommand : ICommand
    {
        private readonly Action _execute;

        public RelayCommand(Action execute)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        }

        public bool CanExecute(object parameter) => true;

        public void Execute(object parameter) => _execute();

        public event EventHandler CanExecuteChanged
        {
            add { }
            remove { }
        }
    }
}

Schlussbemerkung

Mit der Programmiersprache C# und dem Grafik-Framework ist es möglich, eine barrierefreie Software zu entwickeln nach der EN 301 549 und der WCAG 2.2 .

Wenn Sie Fragen zu obige Themen haben, schreiben Sie mir eine Mail an info@marlem-software.de oder rufen Sie mich an unter 07072/1278463 .

Zum Weiterlesen

Autor: Markus Lemcke

Ich bin Markus Lemcke, Softwareentwickler, Webentwickler, Appentwickler, Berater und Dozent für barrierefreies Webdesign, barrierefreie Softwareentwicklung mit Java, C# und Python, Barrierefreiheit bei den Betriebssystemen Windows, Android, IOS, Ubuntu und MacOS.