Permalink
Browse files

Improved Accessibility support.

SharpTreeView now exposes the proper UI Automation control types.
Keyboard navigation using the tab key now works properly.
1 parent 3f38fd0 commit 82ca308a3b8825a1bcbe4c5c50d0329a76e96015 @dgrunwald dgrunwald committed Dec 3, 2016
View
@@ -44,7 +44,7 @@
</Window.TaskbarItemInfo>
<DockPanel>
<!-- Main menu -->
- <Menu DockPanel.Dock="Top" Name="mainMenu" Height="23">
+ <Menu DockPanel.Dock="Top" Name="mainMenu" Height="23" KeyboardNavigation.TabNavigation="None">
<MenuItem Header="_File" /> <!-- contents of file menu are added using MEF -->
<MenuItem Header="_View">
<MenuItem Header="Show _internal types and members" IsCheckable="True" IsChecked="{Binding FilterSettings.ShowInternalApi}">
@@ -57,7 +57,7 @@
<!-- ToolBar -->
<ToolBar
Name="toolBar"
- DockPanel.Dock="Top" ToolBarTray.IsLocked="True">
+ DockPanel.Dock="Top" ToolBarTray.IsLocked="True" KeyboardNavigation.TabNavigation="None">
<ToolBar.Resources>
<!-- Make images transparent if menu command is disabled -->
<Style TargetType="{x:Type Image}">
@@ -113,6 +113,7 @@
<!-- Left pane: Tree View of assemblies and classes -->
<tv:SharpTreeView
Name="treeView"
+ AutomationProperties.Name="Assemblies and Classes"
SelectionChanged="TreeView_SelectionChanged"
ShowRoot="False"
AllowDropOrder="True"
@@ -142,7 +143,7 @@
<RowDefinition Height="0" Name="bottomPaneRow" />
</Grid.RowDefinitions>
<Border BorderBrush="Black" BorderThickness="1" Name="updatePanel" Visibility="Collapsed">
- <DockPanel>
+ <DockPanel KeyboardNavigation.TabNavigation="Contained">
<Button DockPanel.Dock="Right" Click="updatePanelCloseButtonClick" MinWidth="0">X</Button>
<StackPanel Orientation="Horizontal">
<TextBlock Name="updatePanelMessage" Margin="4,0" VerticalAlignment="Center">A new ILSpy version is available.</TextBlock>
@@ -152,6 +153,7 @@
</Border>
<controls:DockedPane x:Name="topPane" Grid.Row="1" Title="Top" Visibility="Collapsed"
+ AutomationProperties.Name="Close top pane"
CloseButtonClicked="TopPane_CloseButtonClicked" Margin="0,0,0,3"
BorderThickness="1,1,0,1" />
@@ -181,8 +183,9 @@
Visibility="{Binding Visibility, ElementName=bottomPane}" />
<controls:DockedPane x:Name="bottomPane" Grid.Row="5" Title="Bottom" Visibility="Collapsed"
+ AutomationProperties.Name="Close"
CloseButtonClicked="BottomPane_CloseButtonClicked" Margin="0,3,0,0" BorderThickness="1,1,0,1"/>
</Grid>
</Grid>
</DockPanel>
-</Window>
+</Window>
@@ -8,7 +8,7 @@
<Grid>
<Border BorderThickness="1,1,0,1" BorderBrush="#FF828790">
<Grid>
- <ae:TextEditor Name="textEditor" FontFamily="Consolas" FontSize="10pt" IsReadOnly="True"
+ <ae:TextEditor Name="textEditor" AutomationProperties.Name="Decompilation" FontFamily="Consolas" FontSize="10pt" IsReadOnly="True"
Background="{DynamicResource {x:Static SystemColors.InfoBrushKey}}"
Foreground="{DynamicResource {x:Static SystemColors.InfoTextBrushKey}}">
<ae:TextEditor.Resources>
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -62,6 +62,8 @@
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="System.Xaml" />
+ <Reference Include="UIAutomationProvider" />
+ <Reference Include="UIAutomationTypes" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
@@ -89,7 +91,9 @@
<Compile Include="SharpTreeNodeCollection.cs" />
<Compile Include="SharpTreeNodeView.cs" />
<Compile Include="SharpTreeView.cs" />
+ <Compile Include="SharpTreeViewAutomationPeer.cs" />
<Compile Include="SharpTreeViewItem.cs" />
+ <Compile Include="SharpTreeViewItemAutomationPeer.cs" />
<Compile Include="TreeFlattener.cs" />
<AppDesigner Include="Properties\" />
<Compile Include="TreeTraversal.cs" />
@@ -106,4 +110,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project>
+</Project>
@@ -343,8 +343,12 @@ object OnFocusItem(object item)
return null;
}
+ protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
+ {
+ return new SharpTreeViewAutomationPeer(this);
+ }
#region Track selection
-
+
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
foreach (SharpTreeNode node in e.RemovedItems) {
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Automation;
+using System.Windows.Automation.Peers;
+
+namespace ICSharpCode.TreeView
+{
+ class SharpTreeViewAutomationPeer : FrameworkElementAutomationPeer
+ {
+ internal SharpTreeViewAutomationPeer(SharpTreeView owner ): base(owner)
+ {
+ }
+ //private SharpTreeView SharpTreeView { get { return (SharpTreeView)base.Owner; } }
+ protected override AutomationControlType GetAutomationControlTypeCore()
+ {
+ return AutomationControlType.Tree;
+ }
+ }
+}
@@ -44,6 +44,11 @@ protected override void OnKeyDown(KeyEventArgs e)
}
}
+ protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
+ {
+ return new SharpTreeViewItemAutomationPeer(this);
+ }
+
#region Mouse
Point startPoint;
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Automation;
+using System.Windows.Automation.Peers;
+using System.Windows.Automation.Provider;
+
+namespace ICSharpCode.TreeView
+{
+ class SharpTreeViewItemAutomationPeer : FrameworkElementAutomationPeer, IExpandCollapseProvider
+ {
+ internal SharpTreeViewItemAutomationPeer(SharpTreeViewItem owner)
+ : base(owner)
+ {
+ SharpTreeViewItem.DataContextChanged += OnDataContextChanged;
+ SharpTreeNode node = SharpTreeViewItem.DataContext as SharpTreeNode;
+ if (node == null) return;
+
+ node.PropertyChanged += OnPropertyChanged;
+
+ }
+ private SharpTreeViewItem SharpTreeViewItem { get { return (SharpTreeViewItem)base.Owner; } }
+ protected override AutomationControlType GetAutomationControlTypeCore()
+ {
+ return AutomationControlType.TreeItem;
+ }
+
+ public override object GetPattern(PatternInterface patternInterface)
+ {
+ if (patternInterface == PatternInterface.ExpandCollapse)
+ return this;
+ return base.GetPattern(patternInterface);
+ }
+ public void Collapse()
+ {
+ }
+
+ public void Expand()
+ {
+ }
+
+ public ExpandCollapseState ExpandCollapseState
+ {
+ get {
+ SharpTreeNode node = SharpTreeViewItem.DataContext as SharpTreeNode;
+ if (node == null || !node.ShowExpander)
+ return ExpandCollapseState.LeafNode;
+ return node.IsExpanded?ExpandCollapseState.Expanded:ExpandCollapseState.Collapsed;
+ }
+ }
+ private void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName != "IsExpanded") return;
+SharpTreeNode node = sender as SharpTreeNode;
+ if (node == null || node.Children.Count == 0) return;
+ bool newValue = node.IsExpanded;
+ bool oldValue = !newValue;
+ RaisePropertyChangedEvent(
+ ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty,
+ oldValue ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed,
+ newValue ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed);
+ }
+private void OnDataContextChanged(object sender,System.Windows.DependencyPropertyChangedEventArgs e)
+ {
+ SharpTreeNode oldNode = e.OldValue as SharpTreeNode;
+ if (oldNode != null)
+ oldNode.PropertyChanged -= OnPropertyChanged;
+ SharpTreeNode newNode = e.NewValue as SharpTreeNode;
+ if (newNode != null)
+ newNode.PropertyChanged += OnPropertyChanged;
+ }
+ }
+}

0 comments on commit 82ca308

Please sign in to comment.