From ec30c1fac3f935d205b1d6810544f80df9117d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Thu, 9 Jan 2025 12:49:56 +0100 Subject: [PATCH 1/8] Add TreeDataGridAutomationPeer --- .../Peers/TreeDataGridAutomationPeer.cs | 18 ++++++++++++++++++ .../TreeDataGrid.cs | 7 +++++++ 2 files changed, 25 insertions(+) create mode 100644 src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridAutomationPeer.cs diff --git a/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridAutomationPeer.cs b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridAutomationPeer.cs new file mode 100644 index 00000000..39148c55 --- /dev/null +++ b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridAutomationPeer.cs @@ -0,0 +1,18 @@ +using Avalonia.Automation.Peers; + +namespace Avalonia.Controls.Automation.Peers; + +public class TreeDataGridAutomationPeer : ControlAutomationPeer +{ + public TreeDataGridAutomationPeer(TreeDataGrid owner) + : base(owner) + { + } + + public new TreeDataGrid Owner => (TreeDataGrid)base.Owner; + + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.DataGrid; + } +} diff --git a/src/Avalonia.Controls.TreeDataGrid/TreeDataGrid.cs b/src/Avalonia.Controls.TreeDataGrid/TreeDataGrid.cs index 1483405a..f147c672 100644 --- a/src/Avalonia.Controls.TreeDataGrid/TreeDataGrid.cs +++ b/src/Avalonia.Controls.TreeDataGrid/TreeDataGrid.cs @@ -2,6 +2,8 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq; +using Avalonia.Automation.Peers; +using Avalonia.Controls.Automation.Peers; using Avalonia.Controls.Documents; using Avalonia.Controls.Models.TreeDataGrid; using Avalonia.Controls.Primitives; @@ -310,6 +312,11 @@ public bool QueryCancelSelection() return e.Cancel; } + protected override AutomationPeer OnCreateAutomationPeer() + { + return new TreeDataGridAutomationPeer(this); + } + protected virtual TreeDataGridElementFactory CreateDefaultElementFactory() => new TreeDataGridElementFactory(); protected override void OnApplyTemplate(TemplateAppliedEventArgs e) From 405ccfdf45c6e8bbf633173c9937c6bbd7193d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Thu, 9 Jan 2025 12:56:53 +0100 Subject: [PATCH 2/8] Add TreeDataGridRowAutomationPeer --- .../Peers/TreeDataGridRowAutomationPeer.cs | 21 +++++++++++++++++++ .../Primitives/TreeDataGridRow.cs | 7 +++++++ 2 files changed, 28 insertions(+) create mode 100644 src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs diff --git a/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs new file mode 100644 index 00000000..24e5a984 --- /dev/null +++ b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs @@ -0,0 +1,21 @@ +using Avalonia.Automation.Peers; +using Avalonia.Controls.Primitives; + +namespace Avalonia.Controls.Automation.Peers; + +public class TreeDataGridRowAutomationPeer : ControlAutomationPeer +{ + public TreeDataGridRowAutomationPeer(TreeDataGridRow owner) + : base(owner) + { + } + + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.DataItem; + } + + protected override bool IsContentElementCore() => true; + + protected override bool IsControlElementCore() => true; +} diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRow.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRow.cs index 7f345e48..68ee564e 100644 --- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRow.cs +++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRow.cs @@ -1,5 +1,7 @@ using System; using System.Text; +using Avalonia.Automation.Peers; +using Avalonia.Controls.Automation.Peers; using Avalonia.Controls.Metadata; using Avalonia.Controls.Models.TreeDataGrid; using Avalonia.Controls.Selection; @@ -112,6 +114,11 @@ public void Unrealize() CellsPresenter?.Unrealize(); } + protected override AutomationPeer OnCreateAutomationPeer() + { + return new TreeDataGridRowAutomationPeer(this); + } + protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { _treeDataGrid = this.FindLogicalAncestorOfType(); From 46b2a73a4fd14956d6f0465018fce21c3434def4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Thu, 9 Jan 2025 12:57:05 +0100 Subject: [PATCH 3/8] Add TreeDataGridCellAutomationPeer --- .../Peers/TreeDataGridCellAutomationPeer.cs | 23 +++++++++++++++++++ .../Primitives/TreeDataGridCell.cs | 7 ++++++ 2 files changed, 30 insertions(+) create mode 100644 src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridCellAutomationPeer.cs diff --git a/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridCellAutomationPeer.cs b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridCellAutomationPeer.cs new file mode 100644 index 00000000..39960cb4 --- /dev/null +++ b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridCellAutomationPeer.cs @@ -0,0 +1,23 @@ +using Avalonia.Automation.Peers; +using Avalonia.Controls.Primitives; + +namespace Avalonia.Controls.Automation.Peers; + +public class TreeDataGridCellAutomationPeer : ControlAutomationPeer +{ + public TreeDataGridCellAutomationPeer(TreeDataGridCell owner) + : base(owner) + { + } + + public new TreeDataGridCell Owner => (TreeDataGridCell)base.Owner; + + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.Custom; + } + + protected override bool IsContentElementCore() => true; + + protected override bool IsControlElementCore() => true; +} diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridCell.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridCell.cs index 63e2f5ca..fd0618cb 100644 --- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridCell.cs +++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridCell.cs @@ -1,5 +1,7 @@ using System; using System.ComponentModel; +using Avalonia.Automation.Peers; +using Avalonia.Controls.Automation.Peers; using Avalonia.Controls.Metadata; using Avalonia.Controls.Models.TreeDataGrid; using Avalonia.Controls.Selection; @@ -74,6 +76,11 @@ public virtual void Unrealize() Model = null; } + protected override AutomationPeer OnCreateAutomationPeer() + { + return new TreeDataGridCellAutomationPeer(this); + } + protected internal void BeginEdit() { if (!IsEditing) From 4f385ef334ddb2d3c8844a8d3dcc4d2a1e188490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Thu, 9 Jan 2025 13:02:16 +0100 Subject: [PATCH 4/8] Add TreeDataGridColumnHeaderAutomationPeer --- .../TreeDataGridColumnHeaderAutomationPeer.cs | 23 +++++++++++++++++++ .../Primitives/TreeDataGridColumnHeader.cs | 7 ++++++ 2 files changed, 30 insertions(+) create mode 100644 src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridColumnHeaderAutomationPeer.cs diff --git a/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridColumnHeaderAutomationPeer.cs b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridColumnHeaderAutomationPeer.cs new file mode 100644 index 00000000..7ccc4b91 --- /dev/null +++ b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridColumnHeaderAutomationPeer.cs @@ -0,0 +1,23 @@ +using Avalonia.Automation.Peers; +using Avalonia.Controls.Primitives; + +namespace Avalonia.Controls.Automation.Peers; + +public class TreeDataGridColumnHeaderAutomationPeer : ContentControlAutomationPeer +{ + public TreeDataGridColumnHeaderAutomationPeer(TreeDataGridColumnHeader owner) + : base(owner) + { + } + + public new TreeDataGridColumnHeader Owner => (TreeDataGridColumnHeader)base.Owner; + + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.HeaderItem; + } + + protected override bool IsContentElementCore() => false; + + protected override bool IsControlElementCore() => true; +} diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeader.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeader.cs index 8098a82a..42237aa6 100644 --- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeader.cs +++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeader.cs @@ -1,5 +1,7 @@ using System; using System.ComponentModel; +using Avalonia.Automation.Peers; +using Avalonia.Controls.Automation.Peers; using Avalonia.Controls.Models.TreeDataGrid; using Avalonia.Input; using Avalonia.Utilities; @@ -81,6 +83,11 @@ public void Unrealize() UpdatePropertiesFromModel(); } + protected override AutomationPeer OnCreateAutomationPeer() + { + return new TreeDataGridColumnHeaderAutomationPeer(this); + } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); From ab017b3d53185e0b1ad8a23f55c7ef421d550711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Thu, 9 Jan 2025 13:03:48 +0100 Subject: [PATCH 5/8] Add TreeDataGridColumnHeadersPresenterAutomationPeer --- ...ridColumnHeadersPresenterAutomationPeer.cs | 23 +++++++++++++++++++ .../TreeDataGridColumnHeadersPresenter.cs | 7 ++++++ 2 files changed, 30 insertions(+) create mode 100644 src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridColumnHeadersPresenterAutomationPeer.cs diff --git a/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridColumnHeadersPresenterAutomationPeer.cs b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridColumnHeadersPresenterAutomationPeer.cs new file mode 100644 index 00000000..54821cad --- /dev/null +++ b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridColumnHeadersPresenterAutomationPeer.cs @@ -0,0 +1,23 @@ +using Avalonia.Automation.Peers; +using Avalonia.Controls.Primitives; + +namespace Avalonia.Controls.Automation.Peers; + +public class TreeDataGridColumnHeadersPresenterAutomationPeer : ControlAutomationPeer +{ + public TreeDataGridColumnHeadersPresenterAutomationPeer(TreeDataGridColumnHeadersPresenter owner) + : base(owner) + { + } + + public new TreeDataGridColumnHeadersPresenter Owner => (TreeDataGridColumnHeadersPresenter)base.Owner; + + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.Header; + } + + protected override bool IsContentElementCore() => false; + + protected override bool IsControlElementCore() => true; +} diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeadersPresenter.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeadersPresenter.cs index 085dcaba..fe5480ea 100644 --- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeadersPresenter.cs +++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeadersPresenter.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using Avalonia.Automation.Peers; +using Avalonia.Controls.Automation.Peers; using Avalonia.Controls.Models.TreeDataGrid; using Avalonia.Layout; using Avalonia.LogicalTree; @@ -12,6 +14,11 @@ public class TreeDataGridColumnHeadersPresenter : TreeDataGridColumnarPresenterB protected override Orientation Orientation => Orientation.Horizontal; + protected override AutomationPeer OnCreateAutomationPeer() + { + return new TreeDataGridColumnHeadersPresenterAutomationPeer(this); + } + protected override Size ArrangeOverride(Size finalSize) { (Items as IColumns)?.CommitActualWidths(); From fd5be1181273721a4edda595beab07bada7b80b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sat, 16 Aug 2025 13:54:26 +0200 Subject: [PATCH 6/8] Use TreeItem for TreeDataGridRowAutomationPeer --- .../Automation/Peers/TreeDataGridRowAutomationPeer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs index 24e5a984..00c29dc0 100644 --- a/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs +++ b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs @@ -12,7 +12,7 @@ public TreeDataGridRowAutomationPeer(TreeDataGridRow owner) protected override AutomationControlType GetAutomationControlTypeCore() { - return AutomationControlType.DataItem; + return AutomationControlType.TreeItem; } protected override bool IsContentElementCore() => true; From cccc806fb790576ba6216589c9b2d46a6c819af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sat, 16 Aug 2025 13:56:25 +0200 Subject: [PATCH 7/8] Implement IToggleProvider and IValueProvider for TreeDataGridRowAutomationPeer --- .../Peers/TreeDataGridRowAutomationPeer.cs | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs index 00c29dc0..abe5538e 100644 --- a/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs +++ b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridRowAutomationPeer.cs @@ -1,15 +1,42 @@ +using System; using Avalonia.Automation.Peers; +using Avalonia.Automation.Provider; +using Avalonia.Controls.Models.TreeDataGrid; using Avalonia.Controls.Primitives; namespace Avalonia.Controls.Automation.Peers; -public class TreeDataGridRowAutomationPeer : ControlAutomationPeer +public class TreeDataGridRowAutomationPeer : ControlAutomationPeer, IToggleProvider, IValueProvider { public TreeDataGridRowAutomationPeer(TreeDataGridRow owner) : base(owner) { } + public new TreeDataGridRow Owner => (TreeDataGridRow)base.Owner; + + public ToggleState ToggleState + { + get + { + if (Owner.DataContext is IExpander expander) + { + return expander.IsExpanded ? ToggleState.On : ToggleState.Off; + } + return ToggleState.Indeterminate; + } + } + + public bool IsReadOnly => true; + + public string? Value + { + get + { + return Owner.Model?.ToString(); + } + } + protected override AutomationControlType GetAutomationControlTypeCore() { return AutomationControlType.TreeItem; @@ -18,4 +45,17 @@ protected override AutomationControlType GetAutomationControlTypeCore() protected override bool IsContentElementCore() => true; protected override bool IsControlElementCore() => true; + + public void Toggle() + { + if (Owner.DataContext is IExpander expander) + { + expander.IsExpanded = !expander.IsExpanded; + } + } + + public void SetValue(string? value) + { + throw new InvalidOperationException("TreeDataGrid rows are read-only."); + } } From b02607e6204212e9cb967f2ea310cb72edb71240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sat, 16 Aug 2025 13:57:34 +0200 Subject: [PATCH 8/8] Override GetNameCore() for TreeDataGridCellAutomationPeer --- .../Peers/TreeDataGridCellAutomationPeer.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridCellAutomationPeer.cs b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridCellAutomationPeer.cs index 39960cb4..8a11eef6 100644 --- a/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridCellAutomationPeer.cs +++ b/src/Avalonia.Controls.TreeDataGrid/Automation/Peers/TreeDataGridCellAutomationPeer.cs @@ -20,4 +20,20 @@ protected override AutomationControlType GetAutomationControlTypeCore() protected override bool IsContentElementCore() => true; protected override bool IsControlElementCore() => true; + + protected override string? GetNameCore() + { + var name = base.GetNameCore(); + if (!string.IsNullOrEmpty(name)) + { + return name; + } + + return Owner switch + { + TreeDataGridTextCell textCell => textCell.Value, + TreeDataGridTemplateCell templateCell => templateCell.Content?.ToString(), + _ => Owner.Model?.ToString() + }; + } }