Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NavigationView not updating UIA users about changed selection and expand state #2692

Merged
10 changes: 9 additions & 1 deletion dev/Generated/NavigationViewItem.properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ void NavigationViewItemProperties::EnsureProperties()
winrt::name_of<winrt::NavigationViewItem>(),
false /* isAttached */,
ValueHelper<bool>::BoxValueIfNecessary(false),
nullptr);
winrt::PropertyChangedCallback(&OnIsExpandedPropertyChanged));
}
if (!s_MenuItemsProperty)
{
Expand Down Expand Up @@ -149,6 +149,14 @@ void NavigationViewItemProperties::OnIconPropertyChanged(
winrt::get_self<NavigationViewItem>(owner)->OnIconPropertyChanged(args);
}

void NavigationViewItemProperties::OnIsExpandedPropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args)
{
auto owner = sender.as<winrt::NavigationViewItem>();
winrt::get_self<NavigationViewItem>(owner)->OnIsExpandedPropertyChanged(args);
}

void NavigationViewItemProperties::OnMenuItemsPropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args)
Expand Down
4 changes: 4 additions & 0 deletions dev/Generated/NavigationViewItem.properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ class NavigationViewItemProperties
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args);

static void OnIsExpandedPropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args);

static void OnMenuItemsPropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args);
Expand Down
33 changes: 32 additions & 1 deletion dev/NavigationView/NavigationView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,12 @@ void NavigationView::OnNavigationViewItemInvoked(const winrt::NavigationViewItem
if (updateSelection)
{
const auto ip = GetIndexPathForContainer(nvi);

// Determine if we will update collapse/expand which will happen iff the item has children
if (DoesNavigationViewItemHaveChildren(nvi))
{
m_shouldIgnoreUIASelectionRaiseAsExpandCollapseWillRaise = true;
}
UpdateSelectionModelSelection(ip);
}

Expand Down Expand Up @@ -1930,13 +1936,38 @@ void NavigationView::ChangeSelection(const winrt::IInspectable& prevItem, const
UnselectPrevItem(prevItem, nextItem);
ChangeSelectStatusForItem(nextItem, true /*selected*/);

{
auto scopeGuard = gsl::finally([this]()
{
m_shouldIgnoreUIASelectionRaiseAsExpandCollapseWillRaise = false;
});

// Selection changed and we need to notify UIA
// HOWEVER expand collapse can also trigger if an item can expand/collapse
// There are multiple cases when selection changes:
// - Through click on item with no children -> No expand/collapse change
// - Through click on item with children -> Expand/collapse change
// - Through API with item without children -> No expand/collapse change
// - Through API with item with children -> No expand/collapse change
if (!m_shouldIgnoreUIASelectionRaiseAsExpandCollapseWillRaise)
{
if (winrt::AutomationPeer peer = winrt::FrameworkElementAutomationPeer::FromElement(*this))
{
auto navViewItemPeer = peer.as<winrt::NavigationViewAutomationPeer>();
winrt::get_self<NavigationViewAutomationPeer>(navViewItemPeer)->RaiseSelectionChangedEvent(
prevItem, nextItem
);
}
}
}

RaiseSelectionChangedEvent(nextItem, isSettingsItem, recommendedDirection);
AnimateSelectionChanged(nextItem);

if (auto const nvi = NavigationViewItemOrSettingsContentFromData(nextItem))
{
ClosePaneIfNeccessaryAfterItemIsClicked(nvi);
}
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions dev/NavigationView/NavigationView.h
Original file line number Diff line number Diff line change
Expand Up @@ -441,5 +441,7 @@ class NavigationView :
bool m_isOpenPaneForInteraction{ false };

bool m_moveTopNavOverflowItemOnFlyoutClose{ false };

bool m_shouldIgnoreUIASelectionRaiseAsExpandCollapseWillRaise{ false };
};

1 change: 1 addition & 0 deletions dev/NavigationView/NavigationView.idl
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ unsealed runtimeclass NavigationViewItem : NavigationViewItemBase
[WUXC_VERSION_MUXONLY]
{
[MUX_DEFAULT_VALUE("false")]
[MUX_PROPERTY_CHANGED_CALLBACK(TRUE)]
Boolean IsExpanded{ get; set; };
[MUX_PROPERTY_CHANGED_CALLBACK(TRUE)]
[MUX_DEFAULT_VALUE("false")]
Expand Down
17 changes: 17 additions & 0 deletions dev/NavigationView/NavigationViewAutomationPeer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,20 @@ winrt::com_array<winrt::Windows::UI::Xaml::Automation::Provider::IRawElementProv
}
return {};
}

void NavigationViewAutomationPeer::RaiseSelectionChangedEvent(winrt::IInspectable const& oldSelection, winrt::IInspectable const& newSelecttion)
{
if (winrt::AutomationPeer::ListenerExists(winrt::AutomationEvents::SelectionPatternOnInvalidated))
{
if (auto nv = Owner().try_as<winrt::NavigationView>())
{
if (auto nvi = winrt::get_self<NavigationView>(nv)->GetSelectedContainer())
{
if (auto peer = winrt::FrameworkElementAutomationPeer::CreatePeerForElement(nvi))
{
peer.RaiseAutomationEvent(winrt::AutomationEvents::SelectionItemPatternOnElementSelected);
}
}
}
}
}
2 changes: 2 additions & 0 deletions dev/NavigationView/NavigationViewAutomationPeer.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ class NavigationViewAutomationPeer :
bool IsSelectionRequired();
winrt::com_array<winrt::Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple> GetSelection();

void RaiseSelectionChangedEvent(winrt::IInspectable const& oldSelection, winrt::IInspectable const& newSelecttion);

private:
};
13 changes: 13 additions & 0 deletions dev/NavigationView/NavigationViewItem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,19 @@ void NavigationViewItem::SuggestedToolTipChanged(winrt::IInspectable const& newC
m_suggestedToolTipContent.set(newToolTipContent);
}

void NavigationViewItem::OnIsExpandedPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args)
{
if (winrt::AutomationPeer peer = winrt::FrameworkElementAutomationPeer::FromElement(*this))
{
auto navViewItemPeer = peer.as<winrt::NavigationViewItemAutomationPeer>();
winrt::get_self<NavigationViewItemAutomationPeer>(navViewItemPeer)->RaiseExpandCollapseAutomationEvent(
IsExpanded() ?
winrt::ExpandCollapseState::Expanded :
winrt::ExpandCollapseState::Collapsed
);
}
}

void NavigationViewItem::OnIconPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args)
{
UpdateVisualStateNoTransition();
Expand Down
1 change: 1 addition & 0 deletions dev/NavigationView/NavigationViewItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class NavigationViewItem :
void OnApplyTemplate() override;

// Property change callbacks
void OnIsExpandedPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
void OnIconPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
void OnMenuItemsPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
void OnMenuItemsSourcePropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
Expand Down