Reputation: 63
I am developing an App that will display data for each day of the week , Monday to Sunday I would like each day to be a separate tab so you can swipe through the days, Currently i am using a Tab that adds 7 different shellContent pages each one is exactly the same and is bound to a different observable collection in the viewmodel. This does work but there are 2 main issues I am having. 1) as I have created 7 different content pages if i change the layout in one i have to then manually change the layout for all of them, which is tedious and error prone. 2) every time i open a tab it is creating a new instance of the viewmodel and these need to get loaded into the tab page on each swipe which is jarring for the user.
I looked at TabbedPage and this seems to be what i want, I can add one Datatemplate and bind the tabs using the item source however i cannont use TabbedBar with Shell.
How can i resuse the same content for each tab and ideally have all the pages loaded with their data before the user has to swipe. I am ok with the initial loading being a little slower as i can but a loading indicator on it.
currently I am adding them like this
<FlyoutItem Title="Weekly Rota" Icon="team.png">
<Tab>
<ShellContent Title="Monday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate startupPages:WeeklyRotaMonday}"/>
<ShellContent Title="Tuesday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate startupPages:WeeklyRotaTuesday}" />
<ShellContent Title="Wednesday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate startupPages:WeeklyRotaWednesday}" />
<ShellContent Title="Thursday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate startupPages:WeeklyRotaThursday}" />
<ShellContent Title="Friday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate startupPages:WeeklyRotaFriday}" />
<ShellContent Title="Saturday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate startupPages:WeeklyRotaSaturday}" />
<ShellContent Title="Sunday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate startupPages:WeeklyRotaSunday}" />
</Tab>
</FlyoutItem>
the ViewModel has the following Code
public ObservableCollection<DailyData> MondayList { get; set; } = new();
public ObservableCollection<DailyData> TuesdayList { get; } = new();
public ObservableCollection<DailyData> WedensdayList { get; } = new();
The data is then bound to each page via the codebehind of the page
public WeeklyRotaFriday(WeeklyRotaViewModel viewModel)
{
InitializeComponent();
this.BindingContext = viewModel;
viewModel.GetDailyDataCommand.Execute(DayOfWeek.Friday);
}
I understand this approach is far from ideal but I am very new to App Development and and have not been able to find any examples that do exactly what i am trying to do. It does function but there must be a better way to do it.
Upvotes: 3
Views: 1183
Reputation: 4302
You can use only one page and achieve to change content for different day by override OnParentChanging
method.
Add Route to every ShellContent:
<FlyoutItem>
<Tab>
<ShellContent Title="Monday" Route="Monday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate local:MainPage}"/>
<ShellContent Title="Tuesday" Route="Tuesday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate local:MainPage}" />
<ShellContent Title="Wednesday" Route="Wednesday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate local:MainPage}" />
<ShellContent Title="Thursday" Route="Thursday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate local:MainPage}" />
<ShellContent Title="Friday" Route="Friday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate local:MainPage}" />
<ShellContent Title="Saturday" Route="Saturday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate local:MainPage}" />
<ShellContent Title="Sunday" Route="Sunday" Shell.TabBarIsVisible="False" ContentTemplate="{DataTemplate local:MainPage}" />
</Tab>
</FlyoutItem>
Page.xaml:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp2.MainPage">
<ScrollView>
<VerticalStackLayout>
<Label Text="{Binding Selection}"/>
<CollectionView ItemsSource="{Binding WeekList}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Name}"/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Override OnParentChanging
in Page.xaml.cs:
public partial class MainPage : ContentPage
{
VM VM = new VM();
public MainPage()
{
InitializeComponent();
BindingContext = VM;
}
protected override void
OnParentChanging(ParentChangingEventArgs args)
{
base.OnParentChanging(args);
var shellContent = args.NewParent as ShellContent;
var route = shellContent.Route;
switch (route)
{
case "Monday":
VM.Selection = "Wednesday";
break;
case "Tuesday":
VM.Selection = "Tuesday";
VM.WeekList = VM.NameIdList1;
break;
case "Wednesday":
VM.Selection = "Wednesday";
VM.WeekList = VM.NameIdList2;
break;
case "Thursday":
VM.Selection = "Thursday";
break;
case "Friday":
VM.Selection = "Friday";
break;
case "Saturday":
VM.Selection = "Saturday";
break;
case "Sunday":
VM.Selection = "Sunday";
break;
default: break;
}
}
}
ViewModel:
public class VM : INotifyPropertyChanged
{
public ObservableCollection<NameId> WeekList { get; set; } = new();
public ObservableCollection<NameId> NameIdList1 { get; set; }
= new ObservableCollection<NameId>
{
new NameId { Id = "Id A", Name = "Name A" },
new NameId { Id = "Id B", Name = "Name B" },
new NameId { Id = "Id C", Name = "Name C" }
};
public ObservableCollection<NameId> NameIdList2 { get; set; }
= new ObservableCollection<NameId>
{
new NameId { Id = "Id A", Name = "Name 2" },
new NameId { Id = "Id B", Name = "Name 2" },
new NameId { Id = "Id C", Name = "Name 2" }
};
public string selection;
public string Selection
{
get => selection;
set
{
selection = value;
OnPropertyChanged(nameof(Selection));
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Upvotes: 1