Screen reader not reading TextBlock content in WPF application - wpf

I am writing a WPF (.net 5) application which should support accessibility specifically windows narrator to read out the screen text. I am using few TextBlocks and expect that as soon as window is shown narrator will start reading all the text present in the screen one by one.
What I observe is that while the Button's content are read out, any TextBlock content is not read by narrator at all.
How can I make the narrator to read all the content of the window one by one.
<Window x:Class="SampleApp.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:SampleApp"
mc:Ignorable="d"
TabIndex="0"
Focusable="True"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock x:Name="firstText"
Text="This is the first line"
KeyboardNavigation.TabIndex="1"
KeyboardNavigation.TabNavigation="Continue"
AutomationProperties.AutomationId="firstTextBox"
AutomationProperties.Name="This is the first line"
/>
<TextBlock x:Name="secondText"
Text="This is the second line"
KeyboardNavigation.TabIndex="2"
KeyboardNavigation.TabNavigation="Continue"
AutomationProperties.AutomationId="secondTextBox"
AutomationProperties.Name="This is the second line"
/>
</StackPanel>
</Grid>
</Window>

Here is a style I use that makes each textblock focusable when the Narrator is on, but does not create a bunch of extra tabs stops if Narrator is off.
<!-- WCAG variant -->
<Style x:Key="WCAG_TextboxStyle" TargetType="{x:Type TextBlock}"
BasedOn="{StaticResource {x:Type TextBlock}}" >
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
<Setter Property="Focusable" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsNarratorOn}" Value="true">
<Setter Property="KeyboardNavigation.IsTabStop" Value="True"/>
<Setter Property="Focusable" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>

Related

Default Title bar appearing even with WindowChrome set

I'm using WindowChrome, and customising the border and the title bar of my application, and it works fine for the most part:
However, for some reason when I run on a certain Virtual Machine (in this case, a German language one using VMware), a white border and title bar (though with no title) appears, and covers my custom title bar:
The odd thing is that I have tried inspecting the application using Snoop, and even on the VM, Snoop does not seem to acknowledge this bar exists. e.g. hovering over the different WPF components, and if I use Snoop's "magnify" function, the title bar appears correctly!
Where could this title bar be coming from and how to get rid of it?
Here is XAML code for a simple application that exhibits the same problem:
<Window x:Class="XamlMessing.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:XamlMessing"
mc:Ignorable="d"
Title="MainWindow" Height="298" Width="399" Background="#FF590B0B">
<Window.Resources>
<WindowChrome x:Key="MyWindowChrome">
<WindowChrome.CaptionHeight>48</WindowChrome.CaptionHeight>
</WindowChrome>
<Style x:Key="MyWindowStyle" TargetType="{x:Type Window}" BasedOn="{StaticResource {x:Type Window}}">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="ResizeMode" Value="NoResize" />
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="TextOptions.TextFormattingMode" Value="Display" />
<Setter Property="WindowState" Value="Normal" />
<Setter Property="WindowStyle" Value="SingleBorderWindow" />
<Setter Property="WindowChrome.WindowChrome" Value="{StaticResource MyWindowChrome}"/>
</Style>
</Window.Resources>
<Window.Style>
<StaticResource ResourceKey="MyWindowStyle"/>
</Window.Style>
<Grid Margin="0,0,81,107">
<TextBlock HorizontalAlignment="Left" Margin="125,89,0,0" TextWrapping="Wrap" Text="Hello, World" VerticalAlignment="Top" Height="61" Width="175" FontSize="24" Foreground="#FFDAE463"/>
</Grid>
</Window>
OK it seems to be fixed by setting...
<WindowChrome.GlassFrameThickness>0</WindowChrome.GlassFrameThickness>
But I would still be interested to know what was causing it to appear in the first place, since that setting wasn't required on devices other than the VM...

Pin Toggle button style

Hi i want to create a generic style for pin button.
<Window x:Class="TooglePinButtonStyle.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">
<Window.Resources>
<Image x:Key="pinImage"
Width="14"
Height="14"
Source="/TooglePinButtonStyle;component/Images/pin.png" />
<Image x:Key="unPinImage"
Width="14"
Height="14"
Source="/TooglePinButtonStyle;component/Images/unpin.png" />
<Style x:Key="pinButtonStyle"
TargetType="{x:Type ToggleButton}">
<Setter Property="Content" Value="{DynamicResource unPinImage}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="{DynamicResource pinImage}" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<ToggleButton Height="30"
Width="30"
Style="{StaticResource pinButtonStyle}"/>
<ToggleButton Height="30"
Width="30"
Style="{StaticResource pinButtonStyle}"/>
</StackPanel>
</Window>
It works fine when there is only one button but when I have two button the UI crashes with
"Specified element is already the logical child of another element.
Disconnect it first."
exception.
Either make the images non-shared, or set the ContentTemplate to some DataTemplate which contains an image (not a reference to an image), rather than the Content. If you have only one instance of an UI-element you will run into this problem, templates describe what should be created rathen than using instances directly.

Parametrized Style within UserControl?

I used this MSDN tutorial to create an eye candy look for all the Button controls of my window, and that worked fine.
To make it even more reusable, I tried to put all in a UserControl: I created a ImageButton UC, then I encapsulated all that <Style> from <Window.Resources> to <UserControl.Resources>.
Then I changed my Button instances in XAML, from:
<Button Tag="Face.jpg" Content="Foo" />
To:
<uc:ImageButton Tag="Face.jpg" Content="Foo" />
And the style stopped being applied.
Here's the UC code:
<UserControl x:Class="GDTI.UI.Main.View.UserControls.ImageButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<Style TargetType="Button">
<Setter Property="MaxWidth" Value="250" />
<Setter Property="Margin" Value="5" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" >
<Setter.Value>
<SolidColorBrush Color="Orange" Opacity="0.4" />
</Setter.Value>
</Setter>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate >
<StackPanel>
<Image Source="{Binding Tag,
RelativeSource={RelativeSource
FindAncestor,
AncestorType='Button'}}" />
<TextBlock Margin="10"
HorizontalAlignment="Center"
Text="{Binding Content,
RelativeSource={RelativeSource
FindAncestor,
AncestorType='Button'}}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Button/>
What am I missing?
Thank you!
The bindings in the button-style target properties on the button, which no longer has the properties set. You need to forward those to the UserControl if you want to retain the style's integrity:
<!-- Inside UserControl declaration -->
<Button Content="{Binding Caption, RelativeSource={RelativeSource AncestorType=UserControl}}"
Tag="{Binding ImageSource, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
Where Caption and ImageSource should be new dependency properties defined on the UserControl (in code-behind).
Note that you can never bind to Content in a UserControl (hence the Caption property), here the Button itself is the Content of the UserControl.
Alternatively you could directly change the targeting in the style by changing the AncestorType to UserControl which bypasses the Button. Binding beyond the templated control is not exactly good practice but your are still inside the UserControl so it may be forgivable.
Either way this is a bit hacky and it might be better to inherit from Button instead.

Accessing ListBox DisplayMemberPath data value in SelectedItem template

I am attempting to create a generic ListBox control to customize edit in place as well as other features.
In the example below, I want to bind the "Text" property of the ListBox "selected item" to the data value of the DisplayMemberPath in the viewed structure. Such XAML binding expression would replace the question marks in the code (Text="{Binding ????????????????").
Using a ContentPresenter instead of binding the text works for display purposes, but I have not been able to bind to the Text component used on the presenter. An alternative to finding the binding expression is to be able to get the Text content from the ContentPresenter.
I can think of a number of ways to accomplish this through code behind, but I am looking for a XAML solution if such thing exists.
I appreciate any ideas. I am almost sure there is a trivial answer to this, but after spending a couple days on it, I admit a nudge in the right direction would greatly help me.
<Window x:Class="WpfApplication1.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">
<Window.Resources>
<XmlDataProvider x:Key="NobelLaureatesInPhysics"
XPath="/NobelLaureatesInPhysics">
<x:XData>
<NobelLaureatesInPhysics xmlns="">
<NobelLaureate>
<ID>1</ID>
<Name>Wilhelm Röntgen</Name>
<AwardDate>12/10/1901</AwardDate>
</NobelLaureate>
<NobelLaureate>
<ID>2</ID>
<Name>Hendrik Lorentz</Name>
<AwardDate>12/10/1902</AwardDate>
</NobelLaureate>
<NobelLaureate>
<ID>3</ID>
<Name>Pieter Zeeman</Name>
<AwardDate>12/10/1902</AwardDate>
</NobelLaureate>
</NobelLaureatesInPhysics>
</x:XData>
</XmlDataProvider>
<ControlTemplate x:Key="ItemTemplate"
TargetType="ListBoxItem">
<TextBlock Foreground="Black">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
<ControlTemplate x:Key="SelectedItemTemplate"
TargetType="ListBoxItem">
<TextBox Background="Black"
Foreground="White"
Text="{Binding ????????????????"/>
</ControlTemplate>
<Style TargetType="{x:Type ListBoxItem}"
x:Key="ContainerStyle">
<Setter Property="Template"
Value="{StaticResource ItemTemplate}" />
<Style.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Template"
Value="{StaticResource SelectedItemTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="TestListBoxStyle"
TargetType="{x:Type ListBox}">
<Setter Property="ItemContainerStyle"
Value="{DynamicResource ContainerStyle}" />
</Style>
</Window.Resources>
<Grid>
<ListBox Style="{DynamicResource TestListBoxStyle}"
ItemsSource="{Binding Source={StaticResource NobelLaureatesInPhysics}, XPath=NobelLaureate}"
DisplayMemberPath="Name"/>
</Grid>
{Binding Path=DisplayMemberPath, RelativeSource={RelativeSource Mode=FindAncestor, Type={x:Type ListBox}}
That should work

Constraining item heights in WPF ListBox, with indicator

I have a ListBox control in WPF which contains items of variable height (predominantly a large text block, so it's also affected by word wrapping). Since scrolling behaves badly when the height of an individual item gets too high (especially when close to the height of the ListBox itself), I want to constrain the max height of the individual items.
I've done that readily enough, by using a Style to set the MaxHeight of the ListBoxItem container.
My problem is that I would like to detect that an individual item has hit that constraint, and then style it differently.
This was my first attempt:
<Style x:Key="LogContainerStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="MaxHeight" Value="64" />
<EventSetter Event="MouseDoubleClick" Handler="LogEntry_MouseDoubleClick" />
</Style>
<DataTemplate x:Key="LogTemplate">
<Grid>
<TextBlock Text="{Binding Message}" />
<TextBlock x:Name="More" Text="(more)"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
Foreground="DarkGray" Visibility="Collapsed" />
</Grid>
<DataTemplate.Triggers>
<Trigger ... height capped at MaxHeight? ...>
<Setter TargetName="More" Property="Visibility" Value="Visible" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
But I'm not sure how to write the trigger. Alternatives welcome.
Try the code below. I set the ListBoxItem.MaxHeight to 99. I then added a trigger in the DataTemplate that checks the ActualHeight of the root element in the template (i.e. "bd" below) and if it's 99, I change the BorderBrush. Hope this helps.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
ShowActivated="False"
Title="MainWindow" Height="350" Width="525">
<ListBox x:Name="lb">
<ListBox.ItemsSource>
<x:Array Type="{x:Type sys:Double}">
<sys:Double>250</sys:Double>
<sys:Double>100</sys:Double>
<sys:Double>50</sys:Double>
<sys:Double>25</sys:Double>
<sys:Double>99</sys:Double>
<sys:Double>120</sys:Double>
</x:Array>
</ListBox.ItemsSource>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="MaxHeight" Value="99"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border x:Name="bd" BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding}" Height="{Binding}" Background="LightGray"/>
</Border>
<DataTemplate.Triggers>
<Trigger SourceName="bd" Property="ActualHeight" Value="99">
<Setter TargetName="bd" Property="BorderBrush" Value="Red"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>

Resources