如何使用 C++/winRT 为 UWP NavigationView 的菜单动态定义 Headers 和设置?
How to dynamically define Headers and Settings for UWP NavigationView's menu, using C++/winRT?
我正在用 C++ 开发一个 cross-platform 项目,动态生成 UI,我在使用 C++/winRT UWP NavigationView 时遇到两个问题:
- 定义 NavigationViewItemHeader 时,生成的 header 标题不会显示在导航菜单中,space 保持为空,
- 尝试更新导航菜单的 SettingsItem 时,设置导航项的值为 SettingsItem() 返回的 nullptr。
这是我编写的代码,用于从独立于主机管理的项目列表中生成菜单(例如 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;
}
由于我使用自己的字符串格式(我坚持使用旧的 C++ 标准...)和 I18N 支持,我需要先将 UTF8 字符串转换为主机(此处 Windows)在设置文本块的值之前,使用 hstring 类型的 hTag 变量。在调试模式下,文本很好地转码为hstring格式...
令我困惑的是,NavigationSeparator 和 NavigationItem 案例都工作正常,符合 Microsoft 官方文档(包括用于菜单事件处理的 Tag 和 NavigationViewItem 的图标设置)。
我知道这不是处理 UWP 用户界面的“主流 XAML 方式”,但到目前为止,该方法在其他 UI 元素上运行良好。
这是导航视图的屏幕截图,其中 headers 为空 spaces:
此外,在上面的示例中,我在主机导航视图 (_hostNavigationView.MenuItems().Size()) 中记录了菜单项的数量,结果是 7,这是正确的...
最后,这是我在 DEBUG 模式下生成的详细日志:
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-}
非常感谢您帮助解决这两个问题!
此致,
阿尔诺
动态 Headers/Footers 在报告中启用不同的分组选项,例如“按位置”或“按系统按位置”:请注意上面圈出了“报告定义”一词。虽然报表最多可以有三个动态 Headers/Footers,但有些报表只有一个或两个动态组。
根据 Roy 的评论,没有必要使用 TextBlock 来设置 NavigationViewItemHeader 和 NavigationViewItem 的值。相反,这只是将字符串值装箱到 IInspectable object:
中的情况
hItem.Content( winrt::box_value( hTag ) );
现在,我有了正确的导航菜单显示和行为:
谢谢罗伊!
更新:
我还设法更改了 SettingsItem 的标题。根据文档,自定义导航菜单的好时机是在加载视图时。
因此,我 subscribed/registered 到 Loaded() 事件并从那里执行自定义。在导航视图生命周期的那个阶段,SettingsItem() returns 一个有效的 NavigationViewItem 允许我使用相同的字符串装箱方法更改标题。
现在两个问题都解决了!
我正在用 C++ 开发一个 cross-platform 项目,动态生成 UI,我在使用 C++/winRT UWP NavigationView 时遇到两个问题:
- 定义 NavigationViewItemHeader 时,生成的 header 标题不会显示在导航菜单中,space 保持为空,
- 尝试更新导航菜单的 SettingsItem 时,设置导航项的值为 SettingsItem() 返回的 nullptr。
这是我编写的代码,用于从独立于主机管理的项目列表中生成菜单(例如 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;
}
由于我使用自己的字符串格式(我坚持使用旧的 C++ 标准...)和 I18N 支持,我需要先将 UTF8 字符串转换为主机(此处 Windows)在设置文本块的值之前,使用 hstring 类型的 hTag 变量。在调试模式下,文本很好地转码为hstring格式...
令我困惑的是,NavigationSeparator 和 NavigationItem 案例都工作正常,符合 Microsoft 官方文档(包括用于菜单事件处理的 Tag 和 NavigationViewItem 的图标设置)。
我知道这不是处理 UWP 用户界面的“主流 XAML 方式”,但到目前为止,该方法在其他 UI 元素上运行良好。
这是导航视图的屏幕截图,其中 headers 为空 spaces:
此外,在上面的示例中,我在主机导航视图 (_hostNavigationView.MenuItems().Size()) 中记录了菜单项的数量,结果是 7,这是正确的...
最后,这是我在 DEBUG 模式下生成的详细日志:
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-}
非常感谢您帮助解决这两个问题!
此致,
阿尔诺
动态 Headers/Footers 在报告中启用不同的分组选项,例如“按位置”或“按系统按位置”:请注意上面圈出了“报告定义”一词。虽然报表最多可以有三个动态 Headers/Footers,但有些报表只有一个或两个动态组。
根据 Roy 的评论,没有必要使用 TextBlock 来设置 NavigationViewItemHeader 和 NavigationViewItem 的值。相反,这只是将字符串值装箱到 IInspectable object:
中的情况hItem.Content( winrt::box_value( hTag ) );
现在,我有了正确的导航菜单显示和行为:
谢谢罗伊!
更新: 我还设法更改了 SettingsItem 的标题。根据文档,自定义导航菜单的好时机是在加载视图时。
因此,我 subscribed/registered 到 Loaded() 事件并从那里执行自定义。在导航视图生命周期的那个阶段,SettingsItem() returns 一个有效的 NavigationViewItem 允许我使用相同的字符串装箱方法更改标题。
现在两个问题都解决了!