スクリーン リーダー (特に JAWS) をサポートする必要がある WPF アプリケーションがあります。問題は、リスト ビュー アイテムが変更 (追加、削除) された場合、JAWS は何もアナウンスしないことです。目の不自由なユーザーは、何が起こったのかまったくわかりません。リストビューコントロールからアイテムを追加/削除しようとするときに、スクリーンリーダーにテキストを強制的にアナウンスさせる方法はありますか? どうすればそれを行うことができますか?
3 に答える
リーダーがこの機能をサポートしていない場合は、JAWS
によって自分で実装できますSpeechSynthesizer
。音声再生の例:
using System.Speech.Synthesis;
SpeechSynthesizer MySpeechSynthesizer = new SpeechSynthesizer();
MySpeechSynthesizer.Speak("Hello!");
ObservableCollection
が割り当てられているの例を使用しましたListBox
。コレクションで実行された行為の列挙を含むObservableCollection
eventです[MSDN] :CollectionChanged
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.
これevent
は次のように実装されます。
// 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
}
}
以下は私の例です:
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);
}
}
問題なく、アイテムの複製テキストを追加できAdd/Remove
ます。.wav
次を使用して再生ファイルを追加することもできますPromptBuilder
。
PromptBuilder MyPromptBuilder = new PromptBuilder();
MyPromptBuilder.AppendAudio("SomeFile.wav");
JAWS は、フォーカスを取得したコントロールにのみ応答します。アプリケーションで同様の機能が必要であり、次の方法で解決しました。
2 つの非表示のテキスト ボックス コントロールをレイアウトに追加します。
<!--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"/>
メッセージをアナウンスするクラスを追加します。信頼性を高めるには、複数のコントロール間でフォーカスを渡す間に一時停止する必要があることがわかりました。そうしないと、JAWS はメッセージを確実に通知しません。
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); } }
メッセージを発表します。単にアナウンスを行うか、Announced イベントを使用してアナウンスを行い、アナウンスが行われた後に追加の作業を行うことができます。
データ・グリッドにデータがロードされるまでお待ちくださいというアナウンスをユーザーに通知します。
// 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(); };
データがデータ グリッドに読み込まれたことをアナウンスします。
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); } }
これを使用すると、Announce() 呼び出しを使用するだけで、いつでもアナウンスを行うことができます。私はもともとこれをSilverlight用に実装しました。WPF でも動作するはずです。