UWP导航视图标题头

6
我正在尝试制作一个使用NavigationView的UWP应用程序。我的问题是如何找到一种方法来使当前显示页面的Header发生变化。我的应用程序基于微软UWP示例"AppUIBasics"。在示例中,NavigationViewHeader始终显示为“欢迎”,因为它被硬编码了,但我希望它根据所选页面而改变。 MainPage.xaml
 <NavigationView x:Name="NavView"
                ItemInvoked="NavView_ItemInvoked"
                SelectionChanged="NavView_SelectionChanged"
                Loaded="NavView_Loaded"
                Canvas.ZIndex="0">

    <NavigationView.HeaderTemplate>
        <DataTemplate>
            <Grid Margin="24,10,0,0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <TextBlock x:Name="appTitle" Style="{StaticResource TitleTextBlockStyle}"
                       FontSize="28"
                       VerticalAlignment="Center"
                       Text="Welcome"/>
                <CommandBar Grid.Column="1"
                        HorizontalAlignment="Right"
                        VerticalAlignment="Top"
                        DefaultLabelPosition="Right"
                        Background="{ThemeResource SystemControlBackgroundAltHighBrush}">
                    <AppBarButton Label="Refresh" Icon="Refresh"/>
                    <AppBarButton Label="Import" Icon="Import"/>
                </CommandBar>
            </Grid>
        </DataTemplate>
    </NavigationView.HeaderTemplate>

    <NavigationView.MenuItems>
        <NavigationViewItem x:Uid="HomeNavItem" Content="" Tag="home">
            <NavigationViewItem.Icon>
                <FontIcon Glyph="&#xE10F;"/>
            </NavigationViewItem.Icon>
        </NavigationViewItem>
        <NavigationViewItemSeparator/>
        <NavigationViewItem x:Uid="ConnectionNavItem" Icon="world" Content="" Tag="connection"/>
        <NavigationViewItem x:Uid="CameraNavItem" Icon="video" Content="" Tag="camera"/>
    </NavigationView.MenuItems>

    <Frame x:Name="rootFrame" Margin="24">
        <Frame.ContentTransitions>
            <TransitionCollection>
                <NavigationThemeTransition/>
            </TransitionCollection>
        </Frame.ContentTransitions>
    </Frame>

</NavigationView>

MainPage.xaml.cs:

 public sealed partial class MainPage : Page {
    public static MainPage Current;
    public static Frame RootFrame = null;

    //private RootFrameNavigationHelper _navHelper;
    private ResourceLoader _resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();

    public MainPage() {
        this.InitializeComponent();

        this.Loaded += (sender, args) => {
            Current = this;
            var titleBar = Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().TitleBar;
        };
    }

    public Frame AppFrame { get { return this.rootFrame; } }

    private void NavView_Loaded(object sender, RoutedEventArgs e) {
        // set the initial SelectedItem 
        foreach (NavigationViewItemBase item in NavView.MenuItems) {
            if (item is NavigationViewItem && item.Tag.ToString() == "home") {
                NavView.SelectedItem = item;
                break;
            }
        }
    }

    private void NavView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) {

        if (args.IsSettingsInvoked) {
            rootFrame.Navigate(typeof(SettingsPage));
        } else {
            // find NavigationViewItem with Content that equals InvokedItem
            var item = sender.MenuItems.OfType<NavigationViewItem>().First(x => (string)x.Content == (string)args.InvokedItem);
            NavView_Navigate(item as NavigationViewItem);

        }
    }

    private void NavView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) {
        if (args.IsSettingsSelected) {
            rootFrame.Navigate(typeof(SettingsPage));
        } else {
            NavigationViewItem item = args.SelectedItem as NavigationViewItem;
            NavView_Navigate(item);
        }
    }

    private void NavView_Navigate(NavigationViewItem item) {
        switch (item.Tag) {
            case "home":
                rootFrame.Navigate(typeof(HomePage)); break;
            case "connection":
                rootFrame.Navigate(typeof(ConnectionPage)); break;
            case "camera":
                rootFrame.Navigate(typeof(CameraPage)); break;
        }
    }
}
2个回答

13

首先,您需要从模板中“取消硬编码”标题文本,而不是文本,您可以使用{Binding},它将提供分配给NavigationViewHeader属性的值:

<NavigationView.HeaderTemplate>
    <DataTemplate>
        <Grid Margin="24,10,0,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <TextBlock x:Name="appTitle" Style="{StaticResource TitleTextBlockStyle}"
                FontSize="28"
                VerticalAlignment="Center"
                Text="{Binding}"/>
            <CommandBar Grid.Column="1"
                HorizontalAlignment="Right"
                VerticalAlignment="Top"
                DefaultLabelPosition="Right"
                Background="{ThemeResource SystemControlBackgroundAltHighBrush}">
                <AppBarButton Label="Refresh" Icon="Refresh"/>
                <AppBarButton Label="Import" Icon="Import"/>
            </CommandBar>
        </Grid>
    </DataTemplate>
</NavigationView.HeaderTemplate>

简单的解决方案

现在有两个地方可以设置标题内容。第一个是SelectionChanged事件:

private void NavView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
    if (args.IsSettingsSelected)
    {
        rootFrame.Navigate(typeof(SettingsPage));
        NavView.Header = "Settings";
    }
    else
    {
        NavigationViewItem item = args.SelectedItem as NavigationViewItem;
        NavView_Navigate(item);
        //just example, maybe you want to Content or something else
        NavView.Header = item.Tag.ToString(); 
    }
}

更好的解决方案

您还可以通过添加一个公共方法来设置标题,从而在任何地方设置Header

public void SetHeader(string header)
{
    NavView.Header = header;
}

然后在任何你觉得合适的位置使用MainPage.Current.SetHeader( something )

最佳解决方案

然而,最好的解决方案是创建一个其他页面将从中派生的基类:

public class BasePage : Page
{
    public virtual string Header => "";
}

然后每个具体的页面都可以覆盖此属性:

public sealed partial class HomePage : BasePage
{
    public override string Header => "Home";

    public HomePage()
    {
        this.InitializeComponent();
    }
}

注意 - 记得在XAML中更新页面的基本类型:

<local:BasePage xmlns:local="using:AppNamespace"
    x:Class="AppNamespace.HomePage" ...>
</local:BasePage>

然后在MainPage中,我们使用数据绑定将Header属性绑定到NavigationViewHeader

<NavigationView x:Name="NavView"
                Header="{Binding Path=Content.Header, ElementName=rootFrame}" ...>

感谢您的解决方案和纠正我的问题 :) - cybertronic
当然,很高兴能帮到你 :-)! 祝你编程愉快! - Martin Zikmund
嗨,答案有什么问题吗?我看到你将其标记为未解决。 - Martin Zikmund
其他用户只是复制了我的解决方案,为什么你却接受了他的解决方案呢? - Martin Zikmund
抱歉,我以为我可以将两个答案都标记为解决方案。但是他的回答为什么与您的回答一模一样? - cybertronic
这是与我上一部分相同的解决方案,只不过使用接口而不是基类。甚至绑定也是相同的,只是变量名不同 :-). - Martin Zikmund

0

步骤 1

定义一个接口

interface ISubPage
{
    string NavTitile { get; }
}

步骤2

在子页面中实现此接口

public sealed partial class HomePage : Page, ISubPage
{
    public HomePage()
    {
        InitializeComponent();
    }

    public string NavTitile => "ArticlePage";
}

步骤三

<NavigationView x:Name="NavView" Header="{Binding Path=Content.NavTitile, ElementName=ContentFrame}">
    <NavigationView.MenuItems>
        <NavigationViewItem Icon="Home" Tag="Home" Content="Home"/>
    </NavigationView.MenuItems>

    <Frame x:Name="ContentFrame" Margin="24"/>
</NavigationView>

1
你为什么要在我的解决方案被接受后,基本上只是复制我的解决方案呢? - Martin Zikmund
1
你启发了我,谢谢。我认为使用接口可以更好地解决问题。 - HeroWong
这比其他答案更清晰易读,直截了当。 - Jams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接