diff --git a/dev/NavigationView/NavigationViewItem.cpp b/dev/NavigationView/NavigationViewItem.cpp index fcd804b8fa..367929f74a 100644 --- a/dev/NavigationView/NavigationViewItem.cpp +++ b/dev/NavigationView/NavigationViewItem.cpp @@ -144,9 +144,16 @@ void NavigationViewItem::UpdateRepeaterItemsSource() } return MenuItems().as(); }(); + m_itemsSourceViewCollectionChangedRevoker.revoke(); repeater.ItemsSource(itemsSource); + m_itemsSourceViewCollectionChangedRevoker = repeater.ItemsSourceView().CollectionChanged(winrt::auto_revoke, { this, &NavigationViewItem::OnItemsSourceViewChanged }); } } + +void NavigationViewItem::OnItemsSourceViewChanged(const winrt::IInspectable& /*sender*/, const winrt::NotifyCollectionChangedEventArgs& /*args*/) +{ + UpdateVisualStateForChevron(); +} winrt::UIElement NavigationViewItem::GetSelectionIndicator() const { @@ -468,7 +475,7 @@ void NavigationViewItem::UpdateVisualStateForChevron() bool NavigationViewItem::HasChildren() { - return MenuItems().Size() > 0 || MenuItemsSource() != nullptr || HasUnrealizedChildren(); + return MenuItems().Size() > 0 || (MenuItemsSource() != nullptr && m_repeater.get().ItemsSourceView().Count() > 0) || HasUnrealizedChildren(); } bool NavigationViewItem::ShouldShowIcon() @@ -919,6 +926,7 @@ void NavigationViewItem::UnhookEventsAndClearFields() m_repeaterElementPreparedRevoker.revoke(); m_repeaterElementClearingRevoker.revoke(); m_isEnabledChangedRevoker.revoke(); + m_itemsSourceViewCollectionChangedRevoker.revoke(); m_rootGrid.set(nullptr); m_navigationViewItemPresenter.set(nullptr); diff --git a/dev/NavigationView/NavigationViewItem.h b/dev/NavigationView/NavigationViewItem.h index 99978e0117..52998f3ecc 100644 --- a/dev/NavigationView/NavigationViewItem.h +++ b/dev/NavigationView/NavigationViewItem.h @@ -100,6 +100,7 @@ class NavigationViewItem : bool HasChildren(); void UpdateRepeaterItemsSource(); + void OnItemsSourceViewChanged(const winrt::IInspectable& sender, const winrt::NotifyCollectionChangedEventArgs& args); void ReparentRepeater(); void OnFlyoutClosing(const winrt::IInspectable& sender, const winrt::FlyoutBaseClosingEventArgs& args); void UpdateItemIndentation(); @@ -124,6 +125,7 @@ class NavigationViewItem : winrt::ItemsRepeater::ElementPrepared_revoker m_repeaterElementPreparedRevoker{}; winrt::ItemsRepeater::ElementClearing_revoker m_repeaterElementClearingRevoker{}; + winrt::ItemsSourceView::CollectionChanged_revoker m_itemsSourceViewCollectionChangedRevoker{}; winrt::FlyoutBase::Closing_revoker m_flyoutClosingRevoker{}; winrt::Control::IsEnabledChanged_revoker m_isEnabledChangedRevoker{}; diff --git a/dev/NavigationView/NavigationView_ApiTests/NavigationViewTests.cs b/dev/NavigationView/NavigationView_ApiTests/NavigationViewTests.cs index a3f1c295c5..5825f13199 100644 --- a/dev/NavigationView/NavigationView_ApiTests/NavigationViewTests.cs +++ b/dev/NavigationView/NavigationView_ApiTests/NavigationViewTests.cs @@ -759,5 +759,67 @@ public void VerifyNavigationViewItemInFooterDoesNotCrash() Verify.IsTrue(true); }); } + + [TestMethod] + public void VerifyExpandCollapseChevronVisibility() + { + NavigationView navView = null; + NavigationViewItem parentItem = null; + ObservableCollection children = null; + + RunOnUIThread.Execute(() => + { + navView = new NavigationView(); + Content = navView; + + children = new ObservableCollection(); + parentItem = new NavigationViewItem() { Content = "ParentItem", MenuItemsSource = children }; + + navView.MenuItems.Add(parentItem); + + navView.Width = 1008; // forces the control into Expanded mode so that the menu renders + Content.UpdateLayout(); + + UIElement chevronUIElement = (UIElement)VisualTreeUtils.FindVisualChildByName(parentItem, "ExpandCollapseChevron"); + Verify.IsTrue(chevronUIElement.Visibility == Visibility.Collapsed, "chevron should have been collapsed as NavViewItem has no children"); + + // Add a child to parentItem through the MenuItemsSource API. This should make the chevron visible. + children.Add("Child 1"); + Content.UpdateLayout(); + + Verify.IsTrue(chevronUIElement.Visibility == Visibility.Visible, "chevron should have been visible as NavViewItem now has children"); + + // Remove all children of parentItem. This should collapse the chevron + children.Clear(); + Content.UpdateLayout(); + + Verify.IsTrue(chevronUIElement.Visibility == Visibility.Collapsed, "chevron should have been collapsed as NavViewItem no longer has children"); + + // Add a child to parentItem and set the MenuItemsSource as null. This should collapse the chevron + children.Add("Child 2"); + Content.UpdateLayout(); + + // we are doing this so that when we set MenuItemsSource as null, we can check if the chevron's visibility really changes + Verify.IsTrue(chevronUIElement.Visibility == Visibility.Visible, "chevron should have been visible as NavViewItem now has children"); + + parentItem.MenuItemsSource = null; + Content.UpdateLayout(); + + Verify.IsTrue(chevronUIElement.Visibility == Visibility.Collapsed, "chevron should have been collapsed as NavViewItem no longer has children"); + + // Add a child to parentItem through the MenuItems API. This should make the chevron visible. + parentItem.MenuItems.Add(new NavigationViewItem() { Content = "Child 3" }); + Content.UpdateLayout(); + + Verify.IsTrue(chevronUIElement.Visibility == Visibility.Visible, "chevron should have been visible as NavViewItem now has children"); + + // Remove all children of parentItem. This should collapse the chevron + parentItem.MenuItems.Clear(); + Content.UpdateLayout(); + + Verify.IsTrue(chevronUIElement.Visibility == Visibility.Collapsed, "chevron should have been collapsed as NavViewItem no longer has children"); + }); + } + } } \ No newline at end of file