Skip to content

Added the sample for the TabView KB #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 139 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,139 @@
# How-to-Customize-the-Header-of-the-Selected-Tab-in-.NET-MAUI-TabView-when-using-ItemsSource-binding
This repository contains a sample explaining how to customize the Header of the Selected Tab in .NET MAUI TabView when using ItemsSource binding.
This article explains how to customize the selected tab header in the [.NET MAUI TabView](https://www.syncfusion.com/maui-controls/maui-tab-view) when using the [ItemsSource](https://help.syncfusion.com/cr/maui/Syncfusion.Maui.TabView.SfTabView.html#Syncfusion_Maui_TabView_SfTabView_ItemsSource) property. The `VisualStateManager` is designed to work directly with [TabItem](https://help.syncfusion.com/cr/maui/Syncfusion.Maui.TabView.SfTabItem.html#Syncfusion_Maui_TabView_SfTabItem__ctor) but does not integrate seamlessly with the ItemsSource-based tab binding. To achieve the desired customization of the selected tab header, the [SelectionChanged](https://help.syncfusion.com/cr/maui/Syncfusion.Maui.TabView.SfTabView.html?tabs=tabid-1#Syncfusion_Maui_TabView_SfTabView_SelectionChanged) event can be leveraged, by utilizing the [EventToCommandBehavior](https://learn.microsoft.com/en-us/dotnet/communitytoolkit/maui/behaviors/event-to-command-behavior).

To dynamically change the text color of the selected tab header, follow these steps:

**Model**

```csharp
public class Model: INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;

protected void OnPropertyChanged(string? propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}

private string? name;
public string? Name
{
get { return name; }
set { name = value; OnPropertyChanged("Name"); }
}

private Color? textColor;
public Color? TextColor
{
get { return textColor; }
set { textColor = value; OnPropertyChanged("TextColor"); }
}
}
```

**ViewModel**

In your ViewModel, you will need to define the properties and commands to handle the selection change:

```csharp
public class MainPageViewModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

private ObservableCollection<Model> tabItems;
public ObservableCollection<Model> TabItems
{
get { return tabItems; }
set { tabItems = value; OnPropertyChanged("TabItems"); }
}

private Command<object> selectionChangedCommand;
public Command<object> SelectionChangedCommand
{
get { return selectionChangedCommand; }
set { selectionChangedCommand = value; OnPropertyChanged("SelectionChangedCommand"); }
}

public MainPageViewModel()
{
TabItems = new ObservableCollection<Model>
{
new Model() { Name = "Alexandar", TextColor = Colors.Red },
new Model() { Name = "Gabriella", TextColor = Colors.Black }
// Add more items as needed
};

SelectionChangedCommand = new Command<object>(ExecuteSelectionChangedCommand);
}

public void ExecuteSelectionChangedCommand(object obj)
{
if (obj is SfTabView tabItem)
{
if (TabItems != null)
{
// Ensure the selected index is within the valid range
if (tabItem.SelectedIndex >= 0 && tabItem.SelectedIndex < TabItems.Count)
{
for (int i = 0; i < TabItems.Count; i++)
{
// Set TextColor for selected tab to red, others to black
TabItems[i].TextColor = (i == (int)tabItem.SelectedIndex) ? Colors.Red : Colors.Black;
}
}
}
}
}
}
```

**Explanation**

1. **TextColor Property**: A `TextColor` property is defined within the `Model` class to allow dynamic updates to the text color of the tab headers.
2. **SelectionChangedCommand**: This command is bound to the `SelectionChanged` event of the `.NET MAUI TabView`. When the selection changes, the command is executed with the `.NET MAUI TabView` instance as the command parameter.
3. **ExecuteSelectionChangedCommand Method**: This method resets the text color for all tab items to the default color (black) and updates the text color of the currently selected tab to red.

**XAML**

```xml
<tabView:SfTabView x:Name="tabView" ItemsSource="{Binding TabItems}" TabWidthMode="SizeToContent" TabHeaderPadding="0">
<tabView:SfTabView.Behaviors>
<toolkit:EventToCommandBehavior Command="{Binding SelectionChangedCommand}" CommandParameter="{x:Reference tabView}" EventName="SelectionChanged"/>
</tabView:SfTabView.Behaviors>
<tabView:SfTabView.HeaderItemTemplate>
<DataTemplate >
<Label x:Name="headerlabel" VerticalOptions="Center" Text="{Binding Name}"
TextColor="{Binding TextColor}"/>
</DataTemplate>
</tabView:SfTabView.HeaderItemTemplate>
<tabView:SfTabView.ContentItemTemplate>
<DataTemplate>
<Grid HorizontalOptions="Center" VerticalOptions="Center">
<Label x:Name="contentLabel" Text="{Binding Name}" HorizontalOptions="Center" VerticalOptions="Center"/>
</Grid>
</DataTemplate>
</tabView:SfTabView.ContentItemTemplate>
</tabView:SfTabView>
```

By following these steps, you can effectively customize the selected tab header in a .NET MAUI TabView when using ItemsSource binding.

**Output**

![TabViewHeaderCustomization.gif](https://support.syncfusion.com/kb/agent/attachment/article/18235/inline?token=eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjM0MDUxIiwib3JnaWQiOiIzIiwiaXNzIjoic3VwcG9ydC5zeW5jZnVzaW9uLmNvbSJ9.LFJsmNPHH9vWsR3CpL62ZtwF5lLr3sWpSrgckb-4pCM)

**Requirements to run the demo**

To run the demo, refer to [System Requirements for .NET MAUI](https://help.syncfusion.com/maui/system-requirements)

**Troubleshooting:**

**Path too long exception**

If you are facing path too long exception when building this example project, close Visual Studio and rename the repository to short and build the project.
31 changes: 31 additions & 0 deletions TabViewSample/TabViewSample.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34309.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TabViewSample", "TabViewSample\TabViewSample.csproj", "{E377EC6C-6773-417F-9ED7-7566F6F0D6BB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Release-Xml|Any CPU = Release-Xml|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E377EC6C-6773-417F-9ED7-7566F6F0D6BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E377EC6C-6773-417F-9ED7-7566F6F0D6BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E377EC6C-6773-417F-9ED7-7566F6F0D6BB}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{E377EC6C-6773-417F-9ED7-7566F6F0D6BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E377EC6C-6773-417F-9ED7-7566F6F0D6BB}.Release|Any CPU.Build.0 = Release|Any CPU
{E377EC6C-6773-417F-9ED7-7566F6F0D6BB}.Release|Any CPU.Deploy.0 = Release|Any CPU
{E377EC6C-6773-417F-9ED7-7566F6F0D6BB}.Release-Xml|Any CPU.ActiveCfg = Release|Any CPU
{E377EC6C-6773-417F-9ED7-7566F6F0D6BB}.Release-Xml|Any CPU.Build.0 = Release|Any CPU
{E377EC6C-6773-417F-9ED7-7566F6F0D6BB}.Release-Xml|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B69CA809-EB64-4829-B9A8-BA7F393E582F}
EndGlobalSection
EndGlobal
14 changes: 14 additions & 0 deletions TabViewSample/TabViewSample/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TabViewSample"
x:Class="TabViewSample.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
12 changes: 12 additions & 0 deletions TabViewSample/TabViewSample/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace TabViewSample
{
public partial class App : Application
{
public App()
{
InitializeComponent();

MainPage = new AppShell();
}
}
}
15 changes: 15 additions & 0 deletions TabViewSample/TabViewSample/AppShell.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="TabViewSample.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TabViewSample"
Shell.FlyoutBehavior="Disabled"
Title="TabViewSample">

<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />

</Shell>
10 changes: 10 additions & 0 deletions TabViewSample/TabViewSample/AppShell.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace TabViewSample
{
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
}
}
31 changes: 31 additions & 0 deletions TabViewSample/TabViewSample/MainPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TabViewSample.MainPage"
xmlns:local="clr-namespace:TabViewSample"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:tabView="clr-namespace:Syncfusion.Maui.TabView;assembly=Syncfusion.Maui.TabView">
<ContentPage.BindingContext>
<local:MainPageViewModel/>
</ContentPage.BindingContext>
<Grid>
<tabView:SfTabView x:Name="tabView" ItemsSource="{Binding TabItems}" TabWidthMode="SizeToContent" TabHeaderPadding="0" FlowDirection="RightToLeft">
<tabView:SfTabView.Behaviors>
<toolkit:EventToCommandBehavior Command="{Binding SelectionChangedCommand}" CommandParameter="{x:Reference tabView}" EventName="SelectionChanged"/>
</tabView:SfTabView.Behaviors>
<tabView:SfTabView.HeaderItemTemplate>
<DataTemplate >
<Label x:Name="headerlabel" Padding="15,0,15,0" VerticalTextAlignment="Center" VerticalOptions="Center"
Text="{Binding Name}" TextColor="{Binding TextColor}"/>
</DataTemplate>
</tabView:SfTabView.HeaderItemTemplate>
<tabView:SfTabView.ContentItemTemplate>
<DataTemplate>
<Grid HorizontalOptions="Center" VerticalOptions="Center">
<Label x:Name="contentLabel" TextColor="Black" Text="{Binding Name}" HorizontalOptions="Center" VerticalOptions="Center"/>
</Grid>
</DataTemplate>
</tabView:SfTabView.ContentItemTemplate>
</tabView:SfTabView>
</Grid>
</ContentPage>
12 changes: 12 additions & 0 deletions TabViewSample/TabViewSample/MainPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace TabViewSample
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}

}

29 changes: 29 additions & 0 deletions TabViewSample/TabViewSample/MauiProgram.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Syncfusion.Maui.Core.Hosting;
using Microsoft.Extensions.Logging;
using CommunityToolkit.Maui;

namespace TabViewSample
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureSyncfusionCore()
.UseMauiCommunityToolkit()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});

#if DEBUG
builder.Logging.AddDebug();
#endif

return builder.Build();
}
}
}
40 changes: 40 additions & 0 deletions TabViewSample/TabViewSample/Model/Model.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.ComponentModel;

namespace TabViewSample
{
public class Model : INotifyPropertyChanged
{

public event PropertyChangedEventHandler? PropertyChanged;

protected void OnPropertyChanged(string? propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}

private string? name;

public string? Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}

private Color? textColor;
public Color? TextColor
{
get { return textColor; }
set
{
textColor = value;
OnPropertyChanged("TextColor");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
11 changes: 11 additions & 0 deletions TabViewSample/TabViewSample/Platforms/Android/MainActivity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Android.App;
using Android.Content.PM;
using Android.OS;

namespace TabViewSample
{
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
}
}
16 changes: 16 additions & 0 deletions TabViewSample/TabViewSample/Platforms/Android/MainApplication.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Android.App;
using Android.Runtime;

namespace TabViewSample
{
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}

protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#512BD4</color>
<color name="colorPrimaryDark">#2B0B98</color>
<color name="colorAccent">#2B0B98</color>
</resources>
Loading
Loading