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

Automation Peer fix for Hierarchical NavigationView #2627

Merged
merged 6 commits into from
Jun 12, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions dev/NavigationView/NavigationView.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ class NavigationView :
// Used in AutomationPeer
winrt::ItemsRepeater LeftNavRepeater();
winrt::NavigationViewItem GetSelectedContainer();
winrt::ItemsRepeater GetParentItemsRepeaterForContainer(const winrt::NavigationViewItemBase& nvib);
winrt::IndexPath GetIndexPathForContainer(const winrt::NavigationViewItemBase& nvib);

// Hierarchical related functions
void Expand(const winrt::NavigationViewItem& item);
Expand All @@ -107,7 +109,6 @@ class NavigationView :
int GetIndexFromItem(const winrt::ItemsRepeater& ir, const winrt::IInspectable& data);
static winrt::IInspectable GetItemFromIndex(const winrt::ItemsRepeater& ir, int index);
winrt::IndexPath GetIndexPathOfItem(const winrt::IInspectable& data);
winrt::IndexPath GetIndexPathForContainer(const winrt::NavigationViewItemBase& nvib);
winrt::UIElement GetContainerForIndex(int index);
winrt::NavigationViewItemBase GetContainerForIndexPath(const winrt::IndexPath& ip);
winrt::NavigationViewItemBase GetContainerForIndexPath(const winrt::UIElement& firstContainer, const winrt::IndexPath& ip);
Expand All @@ -118,7 +119,6 @@ class NavigationView :
winrt::IndexPath SearchEntireTreeForIndexPath(const winrt::NavigationViewItem& parentContainer, const winrt::IInspectable& data, const winrt::IndexPath& ip);

winrt::ItemsRepeater GetChildRepeaterForIndexPath(const winrt::IndexPath& ip);
winrt::ItemsRepeater GetParentItemsRepeaterForContainer(const winrt::NavigationViewItemBase& nvib);
winrt::NavigationViewItem GetParentNavigationViewItemForContainer(const winrt::NavigationViewItemBase& nvib);
bool IsContainerTheSelectedItemInTheSelectionModel(const winrt::NavigationViewItemBase& nvib);
bool IsContainerInOverflow(const winrt::NavigationViewItemBase& nvib);
Expand Down
166 changes: 92 additions & 74 deletions dev/NavigationView/NavigationViewItemAutomationPeer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "NavigationView.h"
#include "NavigationViewItemBase.h"
#include "SharedHelpers.h"
#include "NavigationViewHelper.h"


#include "NavigationViewItemAutomationPeer.properties.cpp"
Expand Down Expand Up @@ -83,17 +84,13 @@ int32_t NavigationViewItemAutomationPeer::GetPositionInSetCore()

if (IsSettingsItem())
{

return 1;
}

if (IsOnTopNavigation())
{
if (auto navigationView = GetParentNavigationView())
{
auto topDataProvider = winrt::get_self<NavigationView>(navigationView)->GetTopDataProvider();
positionInSet = GetPositionOrSetCountInTopNavHelper(IsOnTopNavigationOverflow()
? topDataProvider.GetOverflowItems() : topDataProvider.GetPrimaryItems(), AutomationOutput::Position);
}
positionInSet = GetPositionOrSetCountInTopNavHelper(AutomationOutput::Position);
}
else
{
Expand All @@ -114,13 +111,7 @@ int32_t NavigationViewItemAutomationPeer::GetSizeOfSetCore()

if (IsOnTopNavigation())
{
if (auto navview = GetParentNavigationView())
{
auto topNavDataProvider = winrt::get_self<NavigationView>(navview)->GetTopDataProvider();
sizeOfSet = GetPositionOrSetCountInTopNavHelper(IsOnTopNavigationOverflow()
? topNavDataProvider.GetOverflowItems() : topNavDataProvider.GetPrimaryItems(), AutomationOutput::Size);

}
sizeOfSet = GetPositionOrSetCountInTopNavHelper(AutomationOutput::Size);
}
else
{
Expand All @@ -133,9 +124,23 @@ int32_t NavigationViewItemAutomationPeer::GetSizeOfSetCore()
int32_t NavigationViewItemAutomationPeer::GetLevelCore()
{
int32_t level = 0;
if (winrt::NavigationViewItemBase navigationViewItem = Owner().try_as<winrt::NavigationViewItemBase>())
if (winrt::NavigationViewItemBase nvib = Owner().try_as<winrt::NavigationViewItemBase>())
{
return winrt::get_self<NavigationViewItemBase>(navigationViewItem)->Depth();
auto const nvibImpl = winrt::get_self<NavigationViewItemBase>(nvib);
if (nvibImpl->IsTopLevelItem())
{
return 1;
}
else
{
if (auto const navView = GetParentNavigationView())
{
if (auto const indexPath = winrt::get_self<NavigationView>(navView)->GetIndexPathForContainer(nvib))
{
return indexPath.GetSize();
}
}
}
}

return level;
Expand Down Expand Up @@ -279,6 +284,19 @@ NavigationViewRepeaterPosition NavigationViewItemAutomationPeer::GetNavigationVi
return NavigationViewRepeaterPosition::LeftNav;
}

winrt::ItemsRepeater NavigationViewItemAutomationPeer::GetParentRepeater()
{
if (auto const navview = GetParentNavigationView())
{
if (winrt::NavigationViewItemBase navigationViewItem = Owner().try_as<winrt::NavigationViewItemBase>())
{
return winrt::get_self<NavigationView>(navview)->GetParentItemsRepeaterForContainer(navigationViewItem);
}
}
return nullptr;
}


// Get either the position or the size of the set for this particular item in the case of left nav.
// We go through all the items and then we determine if the listviewitem from the left listview can be a navigation view item header
// or a navigation view item. If it's the former, we just reset the count. If it's the latter, we increment the counter.
Expand All @@ -287,54 +305,51 @@ int32_t NavigationViewItemAutomationPeer::GetPositionOrSetCountInLeftNavHelper(A
{
int returnValue = 0;

if (auto const navview = GetParentNavigationView())
if (auto const repeater = GetParentRepeater())
{
if (auto const repeater = winrt::get_self<NavigationView>(navview)->LeftNavRepeater())
if (auto const parent = Navigate(winrt::AutomationNavigationDirection::Parent).try_as<winrt::AutomationPeer>())
{
if (auto const parent = Navigate(winrt::AutomationNavigationDirection::Parent).try_as<winrt::AutomationPeer>())
if (auto const children = parent.GetChildren())
{
if (auto const children = parent.GetChildren())
{
int index = 0;
bool itemFound = false;
int index = 0;
bool itemFound = false;

for (auto const& child : children)
for (auto const& child : children)
{
if (auto dependencyObject = repeater.TryGetElement(index))
{
if (auto dependencyObject = repeater.TryGetElement(index))
if (dependencyObject.try_as<winrt::NavigationViewItemHeader>())
{
if (dependencyObject.try_as<winrt::NavigationViewItemHeader>())
if (automationOutput == AutomationOutput::Size && itemFound)
{
if (automationOutput == AutomationOutput::Size && itemFound)
{
break;
}
else
{
returnValue = 0;
}
break;
}
else if (auto navviewItem = dependencyObject.try_as<winrt::NavigationViewItem>())
else
{
if (navviewItem.Visibility() == winrt::Visibility::Visible)
{
returnValue++;
returnValue = 0;
}
}
else if (auto navviewItem = dependencyObject.try_as<winrt::NavigationViewItem>())
{
if (navviewItem.Visibility() == winrt::Visibility::Visible)
{
returnValue++;

if (winrt::FrameworkElementAutomationPeer::FromElement(navviewItem) == static_cast<winrt::NavigationViewItemAutomationPeer>(*this))
if (winrt::FrameworkElementAutomationPeer::FromElement(navviewItem) == static_cast<winrt::NavigationViewItemAutomationPeer>(*this))
{
if (automationOutput == AutomationOutput::Position)
{
if (automationOutput == AutomationOutput::Position)
{
break;
}
else
{
itemFound = true;
}
break;
}
else
{
itemFound = true;
}
}
}
}
index++;
}
index++;
}
}
}
Expand All @@ -347,49 +362,52 @@ int32_t NavigationViewItemAutomationPeer::GetPositionOrSetCountInLeftNavHelper(A
// Basically, we do the same here as GetPositionOrSetCountInLeftNavHelper without dealing with the listview directly, because
// TopDataProvider provcides two methods: GetOverflowItems() and GetPrimaryItems(), so we can break the loop (in case of position) by
// comparing the value of the FrameworkElementAutomationPeer we can get from the item we're iterating through to this object.
int32_t NavigationViewItemAutomationPeer::GetPositionOrSetCountInTopNavHelper(winrt::IVector<winrt::IInspectable> navigationViewElements, AutomationOutput automationOutput)
int32_t NavigationViewItemAutomationPeer::GetPositionOrSetCountInTopNavHelper(AutomationOutput automationOutput)
{
int32_t returnValue = 0;
bool itemFound = false;

if (auto const navview = GetParentNavigationView())
if (auto const parentRepeater = GetParentRepeater())
{
bool itemFound = false;

for (auto const& child : navigationViewElements)
if (auto const itemsSourceView = parentRepeater.ItemsSourceView())
{
if (auto const childAsNavViewItem = navview.ContainerFromMenuItem(child))
auto numberOfElements = itemsSourceView.Count();

for (int32_t i = 0; i < numberOfElements; i++)
{
if (child.try_as<winrt::NavigationViewItemHeader>())
if (auto child = parentRepeater.TryGetElement(i))
{
if (automationOutput == AutomationOutput::Size && itemFound)
if (child.try_as<winrt::NavigationViewItemHeader>())
{
break;
}
else
{
returnValue = 0;
if (automationOutput == AutomationOutput::Size && itemFound)
{
break;
}
else
{
returnValue = 0;
}
}
}
else if (auto const navviewitem = childAsNavViewItem.try_as<winrt::NavigationViewItem>())
{
if (navviewitem.Visibility() == winrt::Visibility::Visible)
else if (auto const navviewitem = child.try_as<winrt::NavigationViewItem>())
{
returnValue++;

if (winrt::FrameworkElementAutomationPeer::FromElement(navviewitem) == static_cast<winrt::NavigationViewItemAutomationPeer>(*this))
if (navviewitem.Visibility() == winrt::Visibility::Visible)
{
if (automationOutput == AutomationOutput::Position)
{
break;
}
else
returnValue++;

if (winrt::FrameworkElementAutomationPeer::FromElement(navviewitem) == static_cast<winrt::NavigationViewItemAutomationPeer>(*this))
{
itemFound = true;
if (automationOutput == AutomationOutput::Position)
{
break;
}
else
{
itemFound = true;
}
}
}
}
}

}
}
}
Expand Down
3 changes: 2 additions & 1 deletion dev/NavigationView/NavigationViewItemAutomationPeer.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,14 @@ class NavigationViewItemAutomationPeer :
};

winrt::NavigationView GetParentNavigationView();
winrt::ItemsRepeater GetParentRepeater();
bool IsOnTopNavigation();
bool IsOnTopNavigationOverflow();
bool IsSettingsItem();
NavigationViewRepeaterPosition GetNavigationViewRepeaterPosition();
int32_t GetNavigationViewItemCountInPrimaryList();
int32_t GetNavigationViewItemCountInTopNav();
int32_t GetPositionOrSetCountInLeftNavHelper(AutomationOutput automationOutput);
int32_t GetPositionOrSetCountInTopNavHelper(winrt::IVector<winrt::IInspectable> navigationViewElements, AutomationOutput automationOutput);
int32_t GetPositionOrSetCountInTopNavHelper(AutomationOutput automationOutput);
void ChangeSelection(bool isSelected);
};
39 changes: 39 additions & 0 deletions dev/NavigationView/NavigationView_InteractionTests/CommonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,45 @@ public void ItemsAccessibilitySetTest()
}
}

[TestMethod]
public void HierarchyItemsAccessibilitySetAndLevelTest()
{
using (var setup = new TestSetupHelper(new[] { "NavigationView Tests", "HierarchicalNavigationView Markup Test" }))
{
Log.Comment("Setting focus to Menu Item 15");
UIObject menuItem15 = FindElement.ByName("Menu Item 15");
menuItem15.SetFocus();
Wait.ForIdle();

AutomationElement ae = AutomationElement.FocusedElement;
int positionInSet = (int)ae.GetCurrentPropertyValue(AutomationElement.PositionInSetProperty);
int sizeOfSet = (int)ae.GetCurrentPropertyValue(AutomationElement.SizeOfSetProperty);
int itemLevel = (int)ae.GetCurrentPropertyValue(AutomationElement.LevelProperty);

Verify.AreEqual(4, positionInSet, "Position in set");
Verify.AreEqual(15, sizeOfSet, "Size of set");
Verify.AreEqual(1, itemLevel, "Level of item");

Log.Comment("Expanding Menu Item 15.");
InputHelper.LeftClick(menuItem15);
Wait.ForIdle();

Log.Comment("Setting focus to Menu Item 17");
UIObject menuItem17 = FindElement.ByName("Menu Item 17");
menuItem17.SetFocus();
Wait.ForIdle();

ae = AutomationElement.FocusedElement;
positionInSet = (int)ae.GetCurrentPropertyValue(AutomationElement.PositionInSetProperty);
sizeOfSet = (int)ae.GetCurrentPropertyValue(AutomationElement.SizeOfSetProperty);
itemLevel = (int)ae.GetCurrentPropertyValue(AutomationElement.LevelProperty);

Verify.AreEqual(2, positionInSet, "Position in set, not including separator/header");
Verify.AreEqual(3, sizeOfSet, "Size of set");
Verify.AreEqual(2, itemLevel, "Level of item");
}
}

[TestMethod]
public void ItemsSourceAccessibilitySetTest()
{
Expand Down