Skip to content

ContentPresenters created by GridViewRowPresenters are visible to automation #2212

@dpugh

Description

@dpugh
  • .NET Core Version: 4.8
  • Windows version: (winver) 1909 (OS Build 183.63.476(
  • Does the bug reproduce also in WPF for .NET Framework 4.8?: Yes
  • Is this bug related specifically to tooling in Visual Studio (e.g. XAML Designer, Code editing, etc...)? No

If you have a ListView that uses a FrameworkElementFactory, each row in the list is represented by a GridViewRowPresenter. That presenter creates a ContentPresenter for each child.

When the content of the cell is another UIElement, however, the automation tree has two elements for each cell (one for the ContentPresenter and one for the contained UIElement). This causes problems with navigation using caps+arrows (you stop at the ContentPresenter before navigating to the UIElement) and with some (cough, Narrator) screen readers that read out the ContentPresenter as "Custom".

There should be a way to have the automation peers of the GridViewRowPresenter skip the ContentPresenters of cells that have a UIElement as their content (for example, provide a way to specify the AutomationPeers of the content created using a FrameworkElementFactory).

See the following source for code that replicates the problem.
public partial class MainWindow : Window
{
private readonly ObservableCollection _source;

    public MainWindow()
    {
        InitializeComponent();

        _source = new ObservableCollection<RowViewModel>();
        this.View.ItemsSource = _source;

        GridView grid = this.View.View as GridView;
        grid.Columns.Add(CreateGridViewColumn(100.0, "Alpha", 5.0));
        grid.Columns.Add(CreateGridViewColumn(100.0, "Beta", 5.0));
        grid.Columns.Add(CreateGridViewColumn(100.0, "Gamma", 5.0));

        _source.Add(new RowViewModel(1));
        _source.Add(new RowViewModel(2));
        _source.Add(new RowViewModel(3));
    }

    private GridViewColumn CreateGridViewColumn(double width, string name, double padding)
    {
        GridViewColumn column = new GridViewColumn();
        column.Width = width + padding;
        column.Header = name;
        column.CellTemplate = MainWindow.CreateItemDataTemplate(name);

        return column;
    }


    private static DataTemplate CreateItemDataTemplate(string columnName)
    {
        var template = new DataTemplate();

        FrameworkElementFactory factory = new FrameworkElementFactory(typeof(ContentPresenter));
        factory.SetBinding(ContentPresenter.ContentProperty, new Binding(string.Format(CultureInfo.InvariantCulture, "[{0}]", columnName)));

        template.VisualTree = factory;

        return template;
    }
}

class RowViewModel
{
    private readonly string _id;
    private readonly Dictionary<string, object> _rowMap = new Dictionary<string, object>();

    public RowViewModel(int id)
    {
        _id = id.ToString();
    }

    public object this[string columnName]
    {
        get
        {
            if (!_rowMap.TryGetValue(columnName, out object value))
            {
                value = new TextBlock() { Text = columnName + _id };
            }
            return value;
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Enhancement RequestedProduct code improvement that does NOT require public API changes/additions

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions