I have a window with a page named ShellPage
that contains a NavigationView
control and a Frame
that contains the page content. When initializing the ShellPage, I load the ExploreCountriesPage
. The ExploreCountriesPage
contains a list with items to which you can then navigate to a new ExploreRadiosPage
. A parameter is passed to this page with the selected ExploreCountriesPage
list item.
Navigating to a new page doesn't cause me a problem, but I have a problem navigating backwards between pages. The NavigationView has its Back Button, but when I want to go back to the previous page (ExploreCountriesPage
<-- ExploreRadiosPage
) using that button the application crashes and throws an exception.
I linked the NavigationView with the NavigationViewControl_BackRequested
event which should check if it is possible to return to the previous page.
I also registered my pages to service collection using dependency injection in the App.xaml.cs.
What am I doing wrong?
ShellPage.xaml
<Page
x:Class="Rad.io.Client.WinUI.Views.ShellPage">
<Grid>
<NavigationView x:Name="NavigationViewControl"
IsBackButtonVisible="Auto"
PaneDisplayMode="Auto"
ItemInvoked="NavigationViewControl_ItemInvoked"
IsBackEnabled="{x:Bind RootFrame.CanGoBack, Mode=OneWay}"
BackRequested="NavigationViewControl_BackRequested"
Loaded="NavigationViewControl_Loaded">
<Frame Grid.Row="0" x:Name="RootFrame"/>
</Grid>
</NavigationView>
</Grid>
</Page>
ShellPage.xaml.cs
public sealed partial class ShellPage : Page
{
public ShellViewModel ShellViewModel { get; set; }
public ShellPage()
{
this.ShellViewModel = App.Current.Services.GetService<ShellViewModel>();
this.InitializeComponent();
RootFrame.Content = new ExploreCountriesPage();
}
private void NavigationViewControl_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
switch (args.InvokedItemContainer.Tag)
{
case "Explore":
RootFrame.Navigate(typeof(ExploreCountriesPage));
break;
case "Library":
RootFrame.Navigate(typeof(LibraryPage));
break;
}
}
private void NavigationViewControl_BackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
{
if (RootFrame.CanGoBack)
{
RootFrame.GoBack();
}
}
}
ExploreCountriesPage.xaml.cs
public sealed partial class ExploreCountriesPage : Page
{
public ExploreCountriesViewModel CountriesViewModel { get; set; }
public ExploreCountriesPage()
{
this.InitializeComponent();
this.CountriesViewModel = App.Current.Services.GetService<ExploreCountriesViewModel>();
this.DataContext = CountriesViewModel;
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
await CountriesViewModel.InitializeDataAsync();
}
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CountriesViewModel.SelectedItem = (RadioBrowser.Models.NameAndCount)CountriesListView.SelectedItem;
this.Frame.Navigate(typeof(ExploreRadiosPage), CountriesViewModel.SelectedItem);
}
}
ExploreRadiosPage.xaml.cs
public sealed partial class ExploreRadiosPage : Page
{
public ExploreRadiosViewModel ExploreRadiosViewModel { get; set; }
public ExploreRadiosPage()
{
this.InitializeComponent();
this.ExploreRadiosViewModel = App.Current.Services.GetService<ExploreRadiosViewModel>();
this.DataContext = ExploreRadiosViewModel;
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
ExploreRadiosViewModel.SelectedCountry = e.Parameter as NameAndCount;
base.OnNavigatedTo(e);
}
}
ExploreCountriesPage.xaml
<Page
x:Class="Rad.io.Client.WinUI.Views.ExploreCountriesPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Rad.io.Client.WinUI.Views"
xmlns:viewmodels="using:Rad.io.Client.WinUI.ViewModels"
xmlns:nameandcount="using:RadioBrowser.Models"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Explore"
Style="{ThemeResource TitleTextBlockStyle}"/>
<TextBox Text="{x:Bind CountriesViewModel.EntryQuery, Mode=OneWay}" Grid.Row="1" PlaceholderText="Search countries..."/>
<ListView x:Name="CountriesListView"
Grid.Row="2"
ItemsSource="{x:Bind CountriesViewModel.Countries, Mode=OneWay}"
SelectionMode="Single"
SelectionChanged="ListView_SelectionChanged"
SelectedItem="{x:Bind CountriesViewModel.SelectedItem}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="nameandcount:NameAndCount">
<Grid RowSpacing="4" Margin="8">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{x:Bind Name}"/>
<TextBlock Grid.Row="1" Text="{x:Bind Stationcount}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Page>
ExploreRadiosPage.xaml
<?xml version="1.0" encoding="utf-8"?>
<Page
x:Class="Rad.io.Client.WinUI.Views.ExploreRadiosPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Rad.io.Client.WinUI.Views"
xmlns:radiobrowsermodels="using:RadioBrowser.Models"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Explore"
Style="{ThemeResource TitleTextBlockStyle}"/>
<TextBox Text="{x:Bind ExploreRadiosViewModel.EntryQuery, Mode=OneWay}" Grid.Row="1" PlaceholderText="Search countries..."/>
<ListView x:Name="RadiosListView" Grid.Row="2"
ItemsSource="{x:Bind ExploreRadiosViewModel.Stations, Mode=OneWay}"
SelectionChanged="RadiosListView_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate x:DataType="radiobrowsermodels:StationInfo">
<Grid RowSpacing="4" Margin="8">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{x:Bind Name}"/>
<TextBlock Grid.Row="1" Text="{x:Bind Url}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Page>
ExploreCountriesViewModel.cs
public class ExploreCountriesViewModel : INotifyPropertyChanged
{
private readonly IRadioBrowserClient radioBrowserClient;
private readonly INavigationService navigationService;
private List<NameAndCount> _countries;
private List<NameAndCount> filteredCountries;
private NameAndCount selectedItem;
private string entryQuery;
public List<NameAndCount> Countries
{
get => _countries;
set
{
_countries = value;
RaisePropertyChanged();
}
}
public List<NameAndCount> FilteredCountries
{
get
{
return filteredCountries;
}
set
{
if (EntryQuery is null) filteredCountries = Countries;
else
{
filteredCountries = Countries.Where(value => value.Name.Contains(EntryQuery, StringComparison.OrdinalIgnoreCase)).ToList();
}
RaisePropertyChanged();
}
}
public NameAndCount SelectedItem { get; set; }
public string EntryQuery
{
get => entryQuery;
set
{
entryQuery = value;
RaisePropertyChanged();
}
}
public ExploreCountriesViewModel(IRadioBrowserClient radioBrowserClient, INavigationService navigationService)
{
this.radioBrowserClient = radioBrowserClient;
this.navigationService = navigationService;
}
public async Task InitializeDataAsync()
{
try
{
Countries = await radioBrowserClient.Lists.GetCountriesAsync();
foreach (var result in Countries)
{
Debug.WriteLine(result.Name);
}
}
catch (Exception e)
{
Debug.WriteLine(e);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
ExploreRadiosViewModel.cs
public class ExploreRadiosViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private readonly IRadioBrowserClient radioBrowserClient;
private NameAndCount selectedCountry;
private List<StationInfo> stations;
private List<StationInfo> filteredStations;
private string entryQuery;
public List<StationInfo> Stations
{
get => stations;
set
{
stations = value;
RaisePropertyChanged();
}
}
public NameAndCount SelectedCountry
{
get => selectedCountry;
set
{
selectedCountry = value;
RaisePropertyChanged();
}
}
public string EntryQuery
{
get => entryQuery;
set
{
entryQuery = value;
RaisePropertyChanged();
}
}
public List<StationInfo> FilteredStations
{
get
{
if (entryQuery is null) return Stations;
return Stations.Where(value => value.Name.Contains(EntryQuery, StringComparison.OrdinalIgnoreCase)).ToList();
}
}
public ExploreRadiosViewModel(IRadioBrowserClient radioBrowserClient)
{
this.radioBrowserClient = radioBrowserClient;
}
public async Task InitializeDataAsync()
{
try
{
Stations = await radioBrowserClient.Search.AdvancedAsync(new AdvancedSearchOptions
{
Country = SelectedCountry.Name
});
foreach (var result in Stations)
{
Debug.WriteLine(result.Name);
}
}
catch (Exception e)
{
Debug.WriteLine(e);
}
}
}