diff --git a/controls/dev/TableView/TableViewAutomationPeer.cpp b/controls/dev/TableView/TableViewAutomationPeer.cpp index 4cc4c5a4d9..6ba4a6c706 100644 --- a/controls/dev/TableView/TableViewAutomationPeer.cpp +++ b/controls/dev/TableView/TableViewAutomationPeer.cpp @@ -5,8 +5,8 @@ #include "common.h" #include "TableView.h" #include "TableViewRow.h" +#include "TableViewColumn.h" #include "TableViewAutomationPeer.h" -#include "TableViewColumnHeaderAutomationPeer.h" #include "TableViewCellAutomationPeer.h" #include "TableViewAutomationHelpers.h" #include "TableViewAutomationPeer.properties.cpp" @@ -305,8 +305,8 @@ winrt::com_array TableViewAutomationPeer::GetC { continue; } - // TableView ownership allows pre-realization enumeration but shares RuntimeId. - auto headerPeer = winrt::make(tableView, column); + // TableView ownership allows pre-realization enumeration; the cached peer keeps RuntimeId stable. + auto const headerPeer = winrt::get_self(column)->GetOrCreateHeaderAutomationPeerInternal(tableView); headers.push_back(ProviderFromPeer(headerPeer)); } } diff --git a/controls/dev/TableView/TableViewCellAutomationPeer.cpp b/controls/dev/TableView/TableViewCellAutomationPeer.cpp index f2ecdb278c..7910fd4204 100644 --- a/controls/dev/TableView/TableViewCellAutomationPeer.cpp +++ b/controls/dev/TableView/TableViewCellAutomationPeer.cpp @@ -4,9 +4,9 @@ #include "pch.h" #include "common.h" #include "TableView.h" +#include "TableViewColumn.h" #include "TableViewTextColumn.h" #include "TableViewRow.h" -#include "TableViewColumnHeaderAutomationPeer.h" #include "TableViewCellAutomationPeer.h" #include "TableViewAutomationHelpers.h" #include "TableViewCellAutomationPeer.properties.cpp" @@ -205,7 +205,7 @@ winrt::com_array TableViewCellAutomationPeer:: { if (auto const owner = winrt::get_self(row)->GetOwningTableView()) { - auto const headerPeer = winrt::make(owner, column); + auto const headerPeer = winrt::get_self(column)->GetOrCreateHeaderAutomationPeerInternal(owner); headers.push_back(ProviderFromPeer(headerPeer)); } } diff --git a/controls/dev/TableView/TableViewColumn.cpp b/controls/dev/TableView/TableViewColumn.cpp index 70b14db3b1..5f79887158 100644 --- a/controls/dev/TableView/TableViewColumn.cpp +++ b/controls/dev/TableView/TableViewColumn.cpp @@ -5,6 +5,7 @@ #include "common.h" #include "TableViewColumn.h" #include "TableView.h" +#include "TableViewColumnHeaderAutomationPeer.h" #include #include @@ -291,6 +292,15 @@ void TableViewColumn::NotifyCellContentChanged() } } +winrt::AutomationPeer TableViewColumn::GetOrCreateHeaderAutomationPeerInternal(winrt::TableView const& owner) +{ + if (!m_headerAutomationPeer) + { + m_headerAutomationPeer = winrt::make(owner, *this); + } + return m_headerAutomationPeer; +} + bool TableViewColumn::SetOwningTableViewInternal(winrt::TableView const& owner) { // Keep the owner weak to avoid TableView -> Columns -> Column -> TableView cycles. @@ -310,6 +320,9 @@ bool TableViewColumn::SetOwningTableViewInternal(winrt::TableView const& owner) else { m_owningTableView = nullptr; + + // The cached peer holds the old owner; drop it so a reattach rebuilds it. + m_headerAutomationPeer = nullptr; return true; } } diff --git a/controls/dev/TableView/TableViewColumn.h b/controls/dev/TableView/TableViewColumn.h index 52efcb834f..980f38906c 100644 --- a/controls/dev/TableView/TableViewColumn.h +++ b/controls/dev/TableView/TableViewColumn.h @@ -64,6 +64,10 @@ class TableViewColumn : void ResetDesiredWidthInternal(); double DesiredWidthInternal() const noexcept { return m_desiredWidth; } + // Returns this column's header automation peer, cached so the peer instance - and therefore its + // UIA RuntimeId - stays stable across enumeration, reorder and virtualization. + winrt::AutomationPeer GetOrCreateHeaderAutomationPeerInternal(winrt::TableView const& owner); + private: // Write the resolved, clamped width into the read-only ActualWidth DP. void UpdateActualWidth(); @@ -72,4 +76,7 @@ class TableViewColumn : double m_desiredWidth{ 0.0 }; weak_ref m_owningTableView{ nullptr }; + + // Cached header automation peer; see GetOrCreateHeaderAutomationPeerInternal. + winrt::AutomationPeer m_headerAutomationPeer{ nullptr }; }; diff --git a/controls/dev/TableView/TableViewColumnHeaderAutomationPeer.cpp b/controls/dev/TableView/TableViewColumnHeaderAutomationPeer.cpp index 7e89925f88..5a37217317 100644 --- a/controls/dev/TableView/TableViewColumnHeaderAutomationPeer.cpp +++ b/controls/dev/TableView/TableViewColumnHeaderAutomationPeer.cpp @@ -62,11 +62,7 @@ winrt::AutomationControlType TableViewColumnHeaderAutomationPeer::GetAutomationC int32_t TableViewColumnHeaderAutomationPeer::GetPositionInSetCore() { - // Every header peer shares the TableView owner, so their auto-generated UIA - // RuntimeIds collide (WinUI AutomationPeer has no overridable GetRuntimeIdCore). - // Expose the 1-based column position so AT (Narrator) can still distinguish and - // announce "column i of n"; combined with the distinct GetNameCore this makes each - // header individually identifiable. + // 1-based column position so AT can announce "column i of n". const auto index = GetColumnIndex(); return index >= 0 ? index + 1 : -1; } diff --git a/controls/dev/TableView/TableViewColumnHeaderAutomationPeer.h b/controls/dev/TableView/TableViewColumnHeaderAutomationPeer.h index 54f02dd5ec..2992c62c66 100644 --- a/controls/dev/TableView/TableViewColumnHeaderAutomationPeer.h +++ b/controls/dev/TableView/TableViewColumnHeaderAutomationPeer.h @@ -7,8 +7,8 @@ #include "TableViewColumnHeaderAutomationPeer.g.h" // UIA peer for a TableView column header; reports header name, type, and bounds. -// Distinct per-column RuntimeIds are not yet implemented; peers share the TableView -// owner-derived identity. TableView ownership allows pre-realization enumeration. +// TableView ownership allows pre-realization enumeration. The peer is cached per column +// (TableViewColumn::GetOrCreateHeaderAutomationPeerInternal) so its RuntimeId stays stable. class TableViewColumnHeaderAutomationPeer : public ReferenceTracker { @@ -19,8 +19,7 @@ class TableViewColumnHeaderAutomationPeer : hstring GetClassNameCore(); hstring GetNameCore(); winrt::AutomationControlType GetAutomationControlTypeCore(); - // Header peers share the TableView owner, so RuntimeIds currently collide; expose - // visible column position so AT can distinguish columns until distinct RuntimeIds are implemented. + // PositionInSet/SizeOfSet announce "column i of n" for AT. int32_t GetPositionInSetCore(); int32_t GetSizeOfSetCore();