Ho un'applicazione WPF che necessita di screen reader di supporto (in particolare JAWS). Il problema è che JAWS non annuncia nulla, quando gli elementi della vista elenco sono cambiati (aggiunti, rimossi). E gli utenti non vedenti non sanno assolutamente cosa sia successo. È possibile forzare lo screen reader ad annunciare del testo quando si tenta di aggiungere/rimuovere elementi dal controllo della visualizzazione elenco? e come posso farlo?Come posso forzare lo screen reader (JAWS) ad annunciare un testo personalizzato, quando sono cambiate le voci della visualizzazione elenco (WPF)?
risposta
Se il lettore JAWS
non supporta questa funzione, è possibile implementarlo da solo SpeechSynthesizer
. Esempio la riproduzione vocale:
using System.Speech.Synthesis;
SpeechSynthesizer MySpeechSynthesizer = new SpeechSynthesizer();
MySpeechSynthesizer.Speak("Hello!");
ho usato l'esempio di un ObservableCollection
che viene assegnato ListBox
. ObservableCollection
è un evento CollectionChanged
, in quanto contiene l'enumerazione di atti compiuti sulla raccolta [MSDN]:
Member name Description
------------ ------------
Add One or more items were added to the collection.
Move One or more items were moved within the collection.
Remove One or more items were removed from the collection.
Replace One or more items were replaced in the collection.
Reset The content of the collection changed dramatically.
Questo event
sarà attuato in questo modo:
// Set the ItemsSource
SampleListBox.ItemsSource = SomeListBoxCollection;
// Set handler on the collection
SomeListBoxCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(SomeListBoxCollection_CollectionChanged);
private void SomeListBoxCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
// Some actions, in our case - speech
}
}
Di seguito è riportato il mio esempio:
XAML
<Window x:Class="JAWShelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
WindowStartupLocation="CenterScreen">
<Grid>
<ListBox Name="MyListBox" DisplayMemberPath="Name" SelectedIndex="0" Width="100" Height="100" Loaded="MyListBox_Loaded" />
<WrapPanel Width="200" Height="30" Margin="40,150,0,0">
<Button Name="AddButton" Padding="5" Content="Add item" VerticalAlignment="Bottom" Click="AddButton_Click" />
<Button Name="RemoveButton" Padding="5" Margin="30,0,0,0" Content="Remove item" VerticalAlignment="Bottom" Click="RemoveButton_Click" />
</WrapPanel>
</Grid>
</Window>
Code behind
// using System.Speech.Synthesis;
// using System.Collections.ObjectModel;
// using System.Collections.Specialized;
public partial class MainWindow : Window
{
public class Person
{
public string Name
{
get;
set;
}
}
private ObservableCollection<Person> DataForListBox = new ObservableCollection<Person>();
public MainWindow()
{
InitializeComponent();
}
private void MyListBox_Loaded(object sender, RoutedEventArgs e)
{
DataForListBox.Add(new Person()
{
Name = "Peter Orange",
});
MyListBox.ItemsSource = DataForListBox;
DataForListBox.CollectionChanged += new NotifyCollectionChangedEventHandler(DataForListBox_CollectionChanged);
}
private void DataForListBox_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
SpeechSynthesizer MySpeechSynthesizer = new SpeechSynthesizer();
MySpeechSynthesizer.Speak("You are add item.");
}
if (e.Action == NotifyCollectionChangedAction.Remove)
{
SpeechSynthesizer MySpeechSynthesizer = new SpeechSynthesizer();
MySpeechSynthesizer.Speak("You are remove item.");
}
}
private void AddButton_Click(object sender, RoutedEventArgs e)
{
DataForListBox.Add(new Person()
{
Name = "Jack Rider",
});
}
private void RemoveButton_Click(object sender, RoutedEventArgs e)
{
DataForListBox.RemoveAt(1);
}
}
senza problemi, è possibile aggiungere il testo riproduzione di Add/Remove
voce. È inoltre possibile aggiungere il gioco .wav
file usando PromptBuilder
:
PromptBuilder MyPromptBuilder = new PromptBuilder();
MyPromptBuilder.AppendAudio("SomeFile.wav");
Grazie. ma vorrei che JAWS annunci il testo. –
JAWS risponderà solo ai controlli che guadagno messa a fuoco. Avevo bisogno di funzionalità simili nella mia applicazione e l'ho risolto con il seguente.
Aggiungere due controlli di casella di testo nascosti al layout.
<!--Controls used to announce accessibility messages for screen readers.--> <TextBox x:Name="ATMessage_Silent" Height="1" Width="1" IsTabStop="False" AutomationProperties.Name=" "/> <TextBox x:Name="ATMessage_Audible" Height="1" Width="1" IsTabStop="False"/>
Aggiungere una classe per annunciare i messaggi. Ho trovato che per renderlo affidabile avevo bisogno di fare una pausa breve tra il passaggio del focus tra più controlli. Altrimenti, JAWS non annuncia in modo affidabile i messaggi.
public class AccessibilityMessage { private AccessibilityMessage(object sender, string message, double delay) { DispatcherTimer sleep = new DispatcherTimer(); int counter = 3; try { if (accessibilityMessageAudibleControl != null && accessibilityMessageSilentControl != null) { sleep.Interval = TimeSpan.FromMilliseconds(delay); // Update the message. accessibilityMessageAudibleControl.SetValue(AutomationProperties.NameProperty, message); // Give focus to the silent control. accessibilityMessageSilentControl.IsTabStop = true; accessibilityMessageSilentControl.Focus(); // Give focus to the message. accessibilityMessageAudibleControl.IsTabStop = true; accessibilityMessageAudibleControl.Focus(); // Use a timer to simulate a sleep. We need to pause briefly to give enough time // for the screen reader to process the focus on the message control. After a brief // pause we will give focus back to the original control. If we do not pause like // this the screen reader will not reliably react to the message. sleep.Tick += (s, e) => { counter--; // Check to see if it is time to focus the original control. if (counter == 0) { // Return focus to the original control that triggered the message. if (sender != null && sender is Control) { // Give focus back to the original control. ((Control)sender).Focus(); } // Exit the timer. sleep.Stop(); // Inform any listeners the message has been announced. if (Announced != null) Announced(this, null); } }; // Start the time. sleep.Start(); } else { throw new Exception("Accessibility message controls are not defined in the Application Manager. Unable to announce accessibility message."); } } catch (Exception ex) { ErrorDialog.Show(ex, sender); } } public event EventHandler Announced; public static AccessibilityMessage Announce(object sender, string message, double delay = 250) { return new AccessibilityMessage(sender, message, delay); } }
Annuncia i tuoi messaggi. Puoi semplicemente fare un annuncio o utilizzare l'evento Annunciato, puoi fare l'annuncio e poi eseguire ulteriori lavori dopo l'annuncio.
Fare un annuncio per informare l'utente di attendere mentre una griglia di dati viene caricata con i dati.
// Pass myGrid as the sender so it will receive focus after the announcement. ApplicationManager.AccessibilityMessage.Announce(myGrid, "Loading purchase orders table, please wait.").Announced += (s, arg) => { // MAKE WEB SERVICE CALL TO RETRIEVE DATA. DataService svc = new DataService(); svc.ListPurchasOrdersCompleted += OnListPurchaseOrders_Completed(); svc.ListPurchaseOrders(); };
Fare l'annuncio che i dati sono stati caricati nella griglia di dati.
private void OnListPurchaseOrders_Completed(object sender, AsyncCompletedEventArgs e) { try { if (e.Error == null) { myGrid.ItemsSource = e.Result(); // Pass myGrid as the sender so it will receive focus after the announcement. AccessibilityMessage.Announce(myGrid, string.Format("Loaded {0} orders into the purchase orders table.", myGrid.Items.Count)); } else { throw e.Error; } } catch (Exception ex) { ErrorDialog.Show(ex, this); } }
Usando questo si può fare annunci quando vuoi semplicemente utilizzando la chiamata Annunciare(). Inizialmente l'ho implementato per Silverlight. Dovrebbe funzionare anche per WPF.
Grazie Eric, sta funzionando bene per me. –
- 1. Perché Chrome ha problemi con lo screen reader JAWS?
- 2. C#: come rilevare se lo screen reader è in esecuzione?
- 3. Console di testo per lo sviluppo in JAWS?
- 4. Come posso forzare la visualizzazione dell'indicatore occupato? (WPF)
- 5. Come impedire a uno screen reader/narratore di leggere i controlli che sono nascosti in WPF?
- 6. Nessun testo visibile sul pulsante, ma necessita di testo per lo screen reader?
- 7. Come posso forzare Vaadin ad aggiornare lo schermo?
- 8. Come faccio a segnalare ad altre app Cocoa che le preferenze sono state cambiate?
- 9. Rx groupby fino a quando le condizioni sono cambiate
- 10. Elenco personalizzato Riferimento con voci dinamiche
- 11. Screen Reader per il test Sito Accessibilità
- 12. Come posso forzare la visualizzazione della GUI di mergetool (kdiff3)?
- 13. Uno screen reader può essere "bloccato" all'interno di un elemento DIV?
- 14. Come rendere visibili i controlli GUI personalizzati agli screen reader?
- 15. Forzare un controllo WPF personalizzato per ridimensionare correttamente
- 16. Come forzare QGLWidget ad aggiornare lo schermo?
- 17. Accessibilità del web - comportamento degli screen reader quando configurato per leggere l'attributo 'title'
- 18. visualizzazione testo cliccabile WPF
- 19. Come posso forzare un'immagine per mantenere le proporzioni in WPF?
- 20. WPF valore combobox e visualizzazione del testo
- 21. Associazione di ComboBox WPF a un elenco personalizzato
- 22. di visualizzazione dati di un oggetto personalizzato per ListBox WPF
- 23. Mantenere le proprietà del mio componente quando vengono cambiate?
- 24. Visualizzazione elenco personalizzato con intestazioni personalizzate Android
- 25. visualizzazione elenco impostare un selettore di ondulazione personalizzato
- 26. Visualizzazione ad albero WPF, come modificare il rientro
- 27. : nessuno rispetto alla visibilità: nascosto rispetto all'indice di testo: 9999 Come si comporta lo screen reader con ciascuno di essi?
- 28. Come implementare un elenco personalizzato in Cocoa?
- 29. come forzare lo scorrimento orizzontale in un elenco HTML usando CSS?
- 30. Come si aggiunge un comando personalizzato indirizzato in WPF?
si potrebbe provare a concentrarsi il nuovo elemento. In genere gli strumenti narratore/accessibilità leggono solo ciò che è focalizzato. – AndrewS