Describe the bug
With the release of WinUI 2.4, this code fails to find NavigationViewItem.MenuItems nested under NavigationViewItems.
ShellViewModel.cs:
private void OnItemInvoked(WinUI.NavigationViewItemInvokedEventArgs args)
{
if (args.IsSettingsInvoked)
{
NavigationService.Navigate(typeof(SettingsViewModel).FullName);
return;
}
if (_navigationView is WinUI.NavigationView)
{
//this line below fails to find the activated MenuItem
var item = _navigationView.MenuItems
.OfType<WinUI.NavigationViewItem>()
.First(menuItem => (string)menuItem.Content == (string)args.InvokedItem);
if (item.GetValue(NavHelper.NavigateToProperty) is string pageKey)
{
NavigationService.Navigate(pageKey);
}
}
}
Thanks for reporting!
You can fix this Issue with some code modifications in ShellViewModel
Add this GetSelectedItem method:
private WinUI.NavigationViewItem GetSelectedItem(IEnumerable<object> menuItems, Func<WinUI.NavigationViewItem, bool> predicate)
{
foreach (var item in menuItems.OfType<WinUI.NavigationViewItem>())
{
if (predicate(item))
{
return item;
}
else if (item.MenuItems.Any())
{
var selectedChild = GetSelectedItem(item.MenuItems, predicate);
if (selectedChild != null)
{
return selectedChild;
}
}
}
return null;
}
Update the OnItemInvoked method:
private void OnItemInvoked(WinUI.NavigationViewItemInvokedEventArgs args)
{
if (args.IsSettingsInvoked)
{
NavigationService.Navigate(typeof(SettingsPage));
return;
}
//REMOVE THAT CODE
//var item = _navigationView.MenuItems
// .OfType<WinUI.NavigationViewItem>()
// .First(menuItem => (string)menuItem.Content == (string)args.InvokedItem);
//var pageType = item.GetValue(NavHelper.NavigateToProperty) as Type;
//NavigationService.Navigate(pageType);
// ADD THAT CODE
var selectedItem = GetSelectedItem(_navigationView.MenuItems, item => (string)item.Content == (string)args.InvokedItem);
if (selectedItem != null)
{
var pageType = selectedItem.GetValue(NavHelper.NavigateToProperty) as Type;
NavigationService.Navigate(pageType);
}
}
Update the Frame_Navigated method:
private void Frame_Navigated(object sender, NavigationEventArgs e)
{
IsBackEnabled = NavigationService.CanGoBack;
if (e.SourcePageType == typeof(SettingsPage))
{
Selected = _navigationView.SettingsItem as WinUI.NavigationViewItem;
return;
}
// REMOVE THAT CODE
//Selected = _navigationView.MenuItems
// .OfType<WinUI.NavigationViewItem>()
// .FirstOrDefault(menuItem => IsMenuItemForPageType(menuItem, e.SourcePageType));
// ADD THAT CODE
var selected = GetSelectedItem(_navigationView.MenuItems, item => IsMenuItemForPageType(item, e.SourcePageType));
if (selected != null)
{
Selected = selected;
}
}
Thank you for reporting the issue we will include this change when we'll update to WinUI 2.4.
Here is an App with these updates.
For my reference, which template needs to change? I was trying to look for it, but couldn't find where to make the change.
I've found an easier way to solve this, I'll update the templates today so you can see in pull request which templates are affected.
private void OnItemInvoked(WinUI.NavigationViewItemInvokedEventArgs args)
{
if (args.IsSettingsInvoked)
{
NavigationService.Navigate(typeof(SettingsPage), null, args.RecommendedNavigationTransitionInfo);
return;
}
if (args.InvokedItemContainer is WinUI.NavigationViewItem selectedItem)
{
var pageType = selectedItem.GetValue(NavHelper.NavigateToProperty) as Type;
NavigationService.Navigate(pageType, null, args.RecommendedNavigationTransitionInfo);
}
}
private void Frame_Navigated(object sender, NavigationEventArgs e)
{
IsBackEnabled = NavigationService.CanGoBack;
if (e.SourcePageType == typeof(SettingsPage))
{
Selected = _navigationView.SettingsItem as WinUI.NavigationViewItem;
return;
}
var selectedItem = GetSelectedItem(_navigationView.MenuItems, e.SourcePageType);
if (selectedItem != null)
{
Selected = selectedItem;
}
}
private WinUI.NavigationViewItem GetSelectedItem(IEnumerable<object> menuItems, Type pageType)
{
foreach (var item in menuItems.OfType<WinUI.NavigationViewItem>())
{
if (IsMenuItemForPageType(item, pageType))
{
return item;
}
var selectedChild = GetSelectedItem(item.MenuItems, pageType);
if (selectedChild != null)
{
return selectedChild;
}
}
return null;
}
@mvegaca, I just copied over the code above, but it's not quite working for me. Is this for the MvvmLight version? The NavigationService.Navigate() don't take the same arguments. I haven't put all my effort into it yet, and will look at it again in the morning.
Edit: I see how it needs to look like for MvvmLight in the pull request. Thanks!
Verified in dev-nightly:
Templates version: 0.22.20150.1
Wizard version: 0.22.20150.1