3

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:

  1. When defining a NavigationViewItemHeader, the resulting header title doesn't show in the navigation menu, the space remains empty,
  2. When trying to update the SettingsItem of the navigation menu, the value of the Settings navigation item is nullptr as returned by SettingsItem().

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:

Actual NavigationView

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

alphafox75
  • 71
  • 7
  • Have you tried to add a breakpoint in the method to see if the code of eNavigationHeader case has been actually executed? When you finished the code, have you tried to get the `hostNavigationView.MenuItems()` to check if it contains the NavigationHeader item? – Roy Li - MSFT Feb 02 '22 at 03:09
  • Hello Roy, I removed the trace/log from the code for readability, but I can assure you the code is executed correctly and that an empty space is showing at the expected header's place. However, I'm wondering if the issue is related to the DisplayMode of the view, i.e. the header could be "pushed" further on the right when in Compact/Minimal mode ? – alphafox75 Feb 02 '22 at 07:23
  • 1
    That's interesting. The DisplayMode should not have an effect on this. Could you please try to directly set the string to the `content` property of the NavigationHeader. Do not set a `TextBlock` control. – Roy Li - MSFT Feb 02 '22 at 08:43
  • Hello Roy, Thank you for your suggestion: how can I do that ? I've seen many examples in C#, not in C++ ! – alphafox75 Feb 02 '22 at 09:02
  • 1
    Well, the [NavigationViewItemHeader .Content Property](https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.contentcontrol.content?view=winrt-22000#windows-ui-xaml-controls-contentcontrol-content) is an object. You just need to set the string to it. – Roy Li - MSFT Feb 02 '22 at 09:10
  • Thank you, Roy, it's working! As mentioned in the answer below, it was just a case of boxing the hstring into an IInspectable object. Now, would you have an idea regarding accessing the SettingsItem() which currently return nullptr? – alphafox75 Feb 02 '22 at 11:33

2 Answers2

0

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:

enter image description here

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!

alphafox75
  • 71
  • 7
-1

Dynamic Headers/Footers enable different grouping options in reports, such as "By Location" or "By Location By System": Note that the words "Report Definitions" are circled above. Although reports can have up to three Dynamic Headers/Footers, some reports only have one or two Dynamic Groups.

ouflak
  • 2,458
  • 10
  • 44
  • 49
  • Hello David, I'm not sure I understand your answer. Are you referring to some BI solution ? I am not building reports here but coding a UWP application. I am not certain you are answering my question ! – alphafox75 Feb 02 '22 at 08:23
  • Stack Overflow is not a forum. If you submit an answer it needs to address the question that is being asked. This proposed answer doesn't. Since you are new you should take the [tour] and visit the [help] to learn how Stack Overflow works. – IInspectable Feb 03 '22 at 09:38