I'm working on a cross-platform project in C++ generating the UI dynamically, and I am struggling with C++/winRT UWP NavigationView on two problems:
Here is the code I wrote for generating the menu from a list of items managed independently from the host (e.g. Windows):
bool
CANavigationView::UpdateHostView( void )
{
TNavigationItemPtr item;
TIndex index;
if( _hostViewUpdateNeeded == false )
return false;
Windows::UI::Xaml::Controls::NavigationViewItemBase hItem( nullptr );
Windows::UI::Xaml::Controls::TextBlock hText( nullptr );
winrt::hstring hTag;
// Remove all navigation items from the current host view:
_hostNavigationView.MenuItems().Clear();
_hostNavigationView.IsSettingsVisible( false );
// Build the navigation menu items:
for( index = 0; index < _navigationItems.CountOfItems(); index++ )
{
item = * _navigationItems.GetItemAtIndex( index );
if( item->identifier == kSettingsItem )
{
_hostNavigationView.IsSettingsVisible( true );
hText = Windows::UI::Xaml::Controls::TextBlock();
CSString::ConvertToUIString( item->title->GetString( gAppLanguageCode ), & hTag );
hText.Text( hTag );
// Issue #1 : cannot access to the Settings item
// _hostNavigationView.SettingsItem().as< Windows::UI::Xaml::Controls::NavigationViewItem >().Content( hText );
// SettingsItem() returns nullptr...
}
else
{
switch( item->type )
{
case eNavigationHeader:
hItem = Windows::UI::Xaml::Controls::NavigationViewItemHeader();
hText = Windows::UI::Xaml::Controls::TextBlock();
CSString::ConvertToUIString( item->title->GetString( gAppLanguageCode ), & hTag );
hText.Text( hTag );
// Issue #2: The header's title is not displayed
hItem.Content( hText );
_hostNavigationView.MenuItems().Append( hItem );
break;
case eNavigationSeparator:
hItem = Windows::UI::Xaml::Controls::NavigationViewItemSeparator();
_hostNavigationView.MenuItems().Append( hItem );
break;
case eNavigationItem:
hItem = Windows::UI::Xaml::Controls::NavigationViewItem();
CSString::ConvertToUIString( CAUIElement::GetStringFromUIIdentifier( item->identifier ), & hTag );
hItem.Tag( winrt::box_value( hTag ) );
hText = Windows::UI::Xaml::Controls::TextBlock();
CSString::ConvertToUIString( item->title->GetString( gAppLanguageCode ), & hTag );
hText.Text( hTag );
hItem.Content( hText );
hItem.as< Windows::UI::Xaml::Controls::NavigationViewItem>().Icon( GetHostIcon( item->icon ) );
_hostNavigationView.MenuItems().Append( hItem );
break;
default:
break;
}
}
}
_hostViewUpdateNeeded = false;
return true;
}
As I'm using my own string format (I'm stuck in old C++ standards...) and I18N support, I need to first convert the UTF8 string to the host (here Windows) before setting the value of the text block, using the hTag variable of type hstring. In debugging mode, the text is well transcoded in the hstring format...
What is puzzling me is the fact that both NavigationSeparator and NavigationItem cases are working fine, in line with the official Microsoft documentation (including the Tag for menu event handling and Icon setting for NavigationViewItem).
I understand this is not the "mainstream XAML way" of working on UWP user interface but so far the approach is working well on other UI elements.
Here is a screenshot of the navigation view with the empty spaces for the headers:
Also, in the example above, I logged the number of menu items in the host navigation view (_hostNavigationView.MenuItems().Size()) and got 7 as a result, which is correct...
At last, here's the detailed log I'm generating in DEBUG mode:
DBG-[000002686A230710]CANavigationView::UpdateDisplayedLanguage() {
DBG-[000002686A230710]CANavigationView::UpdateHostView() {
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item 0, type 2
DBG-[000002686A230710]CANavigationView::UpdateHostView() Header case: Reference Library
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item 1, type 1
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item case
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item 2, type 1
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item case
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item 3, type 1
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item case
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item 4, type 3
DBG-[000002686A230710]CANavigationView::UpdateHostView() Separator case
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item 5, type 2
DBG-[000002686A230710]CANavigationView::UpdateHostView() Header case: Project Library
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item 6, type 1
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item case
DBG-[000002686A230710]CANavigationView::UpdateHostView() Navigation item 7, type 1
DBG-[000002686A230710]CANavigationView::UpdateHostView() Settings case
DBG-[000002686A230710]CANavigationView::UpdateHostView() Value of SettingsItem(): 0000000000000000
DBG-[000002686A230710]CANavigationView::UpdateHostView() Count of menu items for the navigation view: 7 (8)
DBG-}
DBG-}
Your help in solving those two issues would be greatly appreciated !
Best regards,
Arnaud
Based on Roy's comments, it is not necessary to use TextBlock to set the value of both NavigationViewItemHeader and NavigationViewItem. Instead, it is just a case of boxing the string value into an IInspectable object:
hItem.Content( winrt::box_value( hTag ) );
Now, I have the correct display and behavior of the navigation menu:
Thank you, Roy !
UPDATE: I also managed to change the title of the SettingsItem. According to the documentation, a good time to customize the navigation menu is when the view is loaded.
Therefore, I subscribed/registered to the Loaded() event and performed the customization from there. At that stage of the lifecycle of the navigation view, SettingsItem() returns a valid NavigationViewItem allowing me to change the title with the same string boxing approach.
Both problems are solved now!