How to programmatically select a bound `Navigation

2019-08-01 14:52发布

My setup is basically as follows:

  • NavigationView's MenuItemsSource is bound to viewModel.NavItems.

    • NavItems is a computed property of viewModel.
  • The view model class implements INotifyPropertyChanged for binding purpose

  • Books of view model is loaded asynchronously.

What works

The NavigationViewItems show up after the page is reached.

The Problem

I need to set a specified NavigationViewItem as the SelectedItem of the NavigationView. But there's no NavigationViewItem (from viewModel) to use inside OnNavigatedTo(NavigationEventArgs e), because at that point viewModel.NavItems is not ready yet.

So is there a pattern for selecting a NavigationViewItem in this async situation?

XAML

<NavigationView x:Name="navView" 
                MenuItemsSource="{x:Bind viewModel.NavItems, Mode=OneWay}"
                SelectionChanged="NavView_SelectionChanged" >
…

the view model

internal class MainPageViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        // The data service
        private MainDataService mainDataService = new MainDataService();

        private List<Book> books = new List<Book>();
        public List<Book> Books
        {
            get
            {
                return this.books;
            }
            set
            {
                this.books = value;
                this.OnPropertyChanged();
                this.OnPropertyChanged("NavItems");
            }
        }

        public IEnumerable<NavigationViewItemBase> NavItems
        {
            get
            {
                return Books.SelectMany(
                    b => (new List<NavigationViewItemBase> { new NavigationViewItemHeader {
                        Content = b.Title,
                        Tag = b.Title
                    } })
                    .Concat(
                        b.Sections.Select(s => new NavigationViewItem
                        {
                            Content = s.Title,
                            Icon = new FontIcon { Glyph = "\uE8B7", FontFamily = new FontFamily("Segoe MDL2 Assets") }
                        })
                    )
                );
            }
        }

        // @param selectedBookIndex: the index of the book whose first section
        // should be selected.
        public async Task UpdateBooks(int selectedBookIndex)
        {
            await mainDataService.PrepareData();
            this.Books = mainDataService.Books;
        }

        …
    }

1条回答
啃猪蹄的小仙女
2楼-- · 2019-08-01 15:51

So is there a pattern for selecting a NavigationViewItem in this async situation?

For async situation, you need use ObservableCollection but not List. And it represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.

But there's no NavigationViewItem (from viewModel) to use inside OnNavigatedTo(NavigationEventArgs e), because at that point viewModel.NavItems is not ready yet.

Before the data is not ready, you could keep the Frame navigation to the default page that used as placehoder within NavigationView Loaded event. For more you could refer Data binding in depth.

查看更多
登录 后发表回答