UWP中Narrator筛选UI元素:IsTabStop=false无效问题求助
问题与解决方案
问题描述
我有一个XAML页面,包含多个UI元素,希望屏幕阅读器Narrator仅识别指定元素、忽略其他元素。页面包含4个Grid行定义,其中UserControlView1通过Grid.RowSpan=4渲染在最上层,其他UI元素已初始化(出于性能考虑),但在UserControlView1的Visibility设为Collapsed前不会显示。
需求:当UserControlView1显示时,Narrator不识别其他UI元素;当UserControlView1隐藏后,Narrator才开始识别这些元素。我尝试设置IsTabStop=false,但未生效,寻求解决方案。
页面代码
<Page xmlns:mvvm="using:Prism.Windows.Mvvm" mvvm:ViewModelLocator.AutoWireViewModel="True" <!-- some random namespaces declaration --> Loaded="PageLoaded"> <Grid> <Grid.ColumnDefinitions> <!-- some Grid Column definition --> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <!-- "4" Grid Row definition... --> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <ctl:UserControlView2 x:Name="UserControlView2" Grid.Row="1" Grid.ColumnSpan="2" IsTabStop="False"/> <ctl:UserControlView3 x:Name="UserControlView3" Grid.Row="2" Grid.Column="0" IsTabStop="False" /> <!-- I have set IsTabStop to false --> <ctl:UserControlView4 x:Name="UserControlView4" Grid.Row="3" Grid.Column="0" IsTabStop="False" /> <!-- I have set IsTabStop to false --> <ctl:UserControlView1 d:Visibility="Collapsed" x:Name="UserControlView1" x:Load="{x:Bind ViewModel.UserControlView1}" Grid.Row="0" Grid.RowSpan="4" <!-- as it span to four rows the reason being its gets render at top of the screen and other UI element will be there beneath it. --> Grid.ColumnSpan="2" TabIndex="0"/> </Grid> </Page>
解决方案
方法1:结合IsHitTestVisible与AutomationProperties.AccessibilityView
IsTabStop=false仅移除Tab导航权限,无法阻止Narrator扫描元素。要彻底让屏幕阅读器忽略元素,需同时设置两个属性:
IsHitTestVisible="False":阻止元素接收交互事件,同时提示屏幕阅读器跳过AutomationProperties.AccessibilityView="Raw":将元素从可访问树中排除
通过绑定UserControlView1的显示状态,控制下层元素:
<!-- 给每个下层控件添加绑定 --> <ctl:UserControlView2 x:Name="UserControlView2" Grid.Row="1" Grid.ColumnSpan="2" IsTabStop="False" IsHitTestVisible="{x:Bind !ViewModel.UserControlView1, Mode=OneWay}" AutomationProperties.AccessibilityView="{x:Bind ViewModel.UserControlView1, Converter={StaticResource BoolToAccessibilityViewConverter}, Mode=OneWay}"/>
配套转换器代码:
public class BoolToAccessibilityViewConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { // 当UserControlView1显示时,设为Raw(忽略);隐藏时设为Content(正常识别) return (bool)value ? AccessibilityView.Raw : AccessibilityView.Content; } public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } }
方法2:绑定Visibility临时隐藏元素(性能允许时使用)
如果不需要保持下层元素的初始化状态,直接绑定Visibility为Collapsed,Narrator会自动忽略不可见元素:
<ctl:UserControlView2 x:Name="UserControlView2" Grid.Row="1" Grid.ColumnSpan="2" Visibility="{x:Bind ViewModel.UserControlView1, Converter={StaticResource BoolToCollapsedConverter}, Mode=OneWay}"/>
配套转换器:
public class BoolToCollapsedConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { return (bool)value ? Visibility.Collapsed : Visibility.Visible; } public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } }
方法3:批量包裹下层元素统一控制
把所有下层元素放到一个容器中,批量设置可访问属性,减少重复代码:
<Grid> <!-- 下层元素容器,统一控制可访问性 --> <StackPanel AutomationProperties.AccessibilityView="{x:Bind ViewModel.UserControlView1, Converter={StaticResource BoolToAccessibilityViewConverter}}" IsHitTestVisible="{x:Bind !ViewModel.UserControlView1, Mode=OneWay}"> <ctl:UserControlView2 x:Name="UserControlView2" Grid.Row="1" Grid.ColumnSpan="2" IsTabStop="False"/> <ctl:UserControlView3 x:Name="UserControlView3" Grid.Row="2" Grid.Column="0" IsTabStop="False" /> <ctl:UserControlView4 x:Name="UserControlView4" Grid.Row="3" Grid.Column="0" IsTabStop="False" /> </StackPanel> <!-- 顶层元素保持不变 --> <ctl:UserControlView1 d:Visibility="Collapsed" x:Name="UserControlView1" x:Load="{x:Bind ViewModel.UserControlView1}" Grid.Row="0" Grid.RowSpan="4" Grid.ColumnSpan="2" TabIndex="0"/> </Grid>
内容的提问来源于stack exchange,提问作者Ritesh Kumar
相关产品推荐
相关产品推荐

