Skip to content

Commit 16184ce

Browse files
Control Panel: two lists announced their type name to screen readers
Found while driving the Control Panel through UI Automation to capture documentation screenshots: the alias list on the Domains page exposed "hMailServer.ControlPanel.Views.DomainsView+AliasRow" as its accessible name for every row, and the live log exposed "LogsView+LogLine" for every line. Both lists use an ItemTemplate, so the text a sighted user sees comes from a binding - Display and Text respectively - while a ListViewItem's accessible name falls back to ToString() on the bound object. Neither class overrode it, so assistive technology got the CLR type name instead of the content. The live log is the worse of the two: it is the page an administrator is most likely to be reading aloud, or reading with a screen reader, at exactly the moment something has gone wrong. Scope is genuinely these two. The domain, account and distribution-list views on the same page bind plain strings and were always correct, and every other list in the application (IP ranges, queue, routes, rules, certificates, TCP/IP ports) is a DataGrid, which builds a row's name from its cells rather than from ToString(). AddrItem already had an override, which is what the pattern should look like. Verified through the same API that exposed the problem. Before, the Domains page reported one item as "hMailServer.ControlPanel.Views.DomainsView+AliasRow"; it now reports "info@example.com -> sales@example.com". The live log reports 37 items, 0 of which announce a type name. Control Panel builds with -warnaserror and no warnings; its 17 unit tests pass.
1 parent 92a6599 commit 16184ce

2 files changed

Lines changed: 14 additions & 0 deletions

File tree

hmailserver/source/Tools/ControlPanel/Views/DomainsView.xaml.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ public class AliasRow
6161
{
6262
public string Name { get; set; }
6363
public string Display { get; set; }
64+
65+
// The alias list is a ListView with an ItemTemplate, so the visible text
66+
// comes from the Display binding - but a ListViewItem's accessible name
67+
// falls back to ToString() on the bound object. Without this a screen
68+
// reader announces the type name for every alias. The domain, account and
69+
// distribution lists are bound to plain strings and never had the problem.
70+
public override string ToString() => Display;
6471
}
6572

6673
private dynamic OpenSelectedDomain(dynamic domains)

hmailserver/source/Tools/ControlPanel/Views/LogsView.xaml.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ public class LogLine
1818
{
1919
public string Text { get; set; }
2020
public Brush Brush { get; set; }
21+
22+
// The log is a ListBox with an ItemTemplate, so a ListBoxItem's accessible
23+
// name falls back to ToString() on the bound object rather than the text
24+
// shown. Without this a screen reader announces the type name for every
25+
// line of the live log, which is the page an administrator is most likely
26+
// to be reading aloud when something is wrong.
27+
public override string ToString() => Text;
2128
}
2229

2330
private readonly ObservableCollection<LogLine> lines_ = new();

0 commit comments

Comments
 (0)