Sharpnado.Tabs
Sharpnado.Tabs copied to clipboard
Is there an example on how to dynamically create tabs?
This component seems just what I need to implement scrollable tabbed pages. Based on your example I understand how to create a scrollable set of tabs, how to link them to tab contents, and I can manipulate them from xaml. However, I need to craeate tabs and tab content dynamically. Is there an eample on how to do it either fully from C# code, instantiating say UnderlinedTabItems and adding them to the TabHostView and the ViewScroller, or via some templating mechanism and using observable collections.
Use items source property and item template as you would do with a collection view or a bindable layout
TabHostView is done, but ViewSwitcher doesn't seem to have ItemSource and ItemTemplate properties I could set. Am I missing something?
OK, progress: I checked the source and found that ViewSwitcher is derived from grid, so tried to assign items to grid cells - but that didn't work. Then I tried adding items ti MyViewSwitcher.Children, and it seems to be OK, is paged as the bound TabHostView selected item changes. Here's the code so far:
Page XML relevant parts:
<ContentPage.Resources>
<ResourceDictionary>
<!-- Styles reused from https://github.com/roubachof/Sharpnado.Tabs/blob/main/MauiSample/Presentation/Views/TabM.xaml -->
<Style x:Key="ScrollableTabStyle" TargetType="tabs:UnderlinedTabItem"> ... </Style>
<Style x:Key="LabelDescription" TargetType="Label"> ... </Style>
<DataTemplate x:Key="HeaderTemplate">
<!-- Bind Label text to List<string> items -->
<tabs:UnderlinedTabItem
Style="{StaticResource ScrollableTabStyle}"
Label="{Binding}">
</tabs:UnderlinedTabItem>
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<tabs:TabHostView
x:Name="MyTabHostView"
Grid.Row="0"
HeightRequest="50"
SelectedIndex="1"
ShowScrollbar="False"
TabType="Scrollable"
ItemsSource="{Binding HeaderTexts}"
ItemTemplate="{StaticResource HeaderTemplate}">
</tabs:TabHostView>
<tabs:ViewSwitcher
x:Name="MyViewSwitcher"
Grid.Row="1"
Margin="16,0"
VerticalOptions="StartAndExpand"
Animate="False"
SelectedIndex="{Binding Source={x:Reference MyTabHostView}, Path=SelectedIndex, Mode=OneWay}">
<!-- Tab pages are added as Child Items in code behind -->
</tabs:ViewSwitcher>
</Grid>
In code behind:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyPage : ContentPage
{
public MyPage(MyViewModel vm)
{
InitializeComponent();
BindingContext = vm;
int i = 0;
foreach(var contentGroup in vm.ContentGroups)
{
Label label = new Label
{
Text = $"Tab {+i} content",
Style = (Style)this.Resources["LabelDescription"]
};
MyViewSwitcher.Children.Add(label);
}
// Touch TabHostView to populate contents of the inital tab page body.
LanesNamesTabHostView.SelectedIndex = -1;
LanesNamesTabHostView.SelectedIndex = 0;
}
}
I know it's been a long time since you opened this issue, but I've had success with BindableLayouts for this scenario.
In your example you have a view model with two collections, HeaderTexts and ContentGroups, where you want the tabs in the TabHostView to bind to the HeaderTexts objects and the ViewSwitcher to ContentGroups.
Here's how you could use a BindableLayout to create those views in the ViewSwitcher instead of doing it in code behind:
<tabs:TabHostView
x:Name="MyTabHostView"
Grid.Row="0"
HeightRequest="50"
SelectedIndex="1"
ShowScrollbar="False"
TabType="Scrollable"
ItemsSource="{Binding HeaderTexts}"
ItemTemplate="{StaticResource HeaderTemplate}">
</tabs:TabHostView>
<tabs:ViewSwitcher
x:Name="MyViewSwitcher"
Grid.Row="1"
Margin="16,0"
VerticalOptions="StartAndExpand"
Animate="False"
SelectedIndex="{Binding Source={x:Reference MyTabHostView}, Path=SelectedIndex, Mode=OneWay}"
BindableLayout.ItemsSource="{Binding ContentGroups}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label Style={StaticResource LabelDescription} Text="{Binding Description}" />
</DataTemplate>
</BindableLayout.ItemTemplate>
</tabs:ViewSwitcher>
</Grid>