1

I am using Xamarin Community Toolkit TabView for showing tabs on my MainPage, I have two TabViewItems in it and loading ContentView inside the TabViewItem. I want to show a confirmation box to user if any unsaved changes are exist on Tab1 before going to Tab2.

MainPage.xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
             xmlns:pancakeview="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView" xmlns:views="clr-namespace:TimeKeeper.Views"
             x:Class="TimeKeeper.MainPage"
             BackgroundColor="{StaticResource LightBgColor}"
             Title="Home"
             NavigationPage.HasNavigationBar="True"
             Shell.NavBarIsVisible="True"
             >
    <ContentPage.ToolbarItems>
       
    </ContentPage.ToolbarItems>
    <ContentPage.Resources>
        <ResourceDictionary>
            <ControlTemplate
                x:Key="TabItemTemplate">    
                <pancakeview:PancakeView HeightRequest="70" WidthRequest="70" CornerRadius="35" HorizontalOptions="Center" VerticalOptions="Center" BackgroundColor="{TemplateBinding CurrentBadgeBackgroundColor}">
                    <StackLayout VerticalOptions="Center" Spacing="2">
                        <Image Source="{TemplateBinding CurrentIcon}" HeightRequest="24" HorizontalOptions="Center" xct:IconTintColorEffect.TintColor="{TemplateBinding CurrentTextColor}"/>
                        <Label Text="{TemplateBinding Text}" TextColor="{TemplateBinding CurrentTextColor}" FontSize="10" FontFamily="Medium" HorizontalOptions="Center"/>
                    </StackLayout>
                </pancakeview:PancakeView>
            </ControlTemplate>

            <Style
                x:Key="CustomTabStyle"
                TargetType="xct:TabView">
                <Setter
                    Property="IsTabTransitionEnabled"
                    Value="True" />
                <Setter
                    Property="TabStripHeight"
                    Value="{OnPlatform Android='90', iOS='100'}" />
                <Setter
                    Property="TabContentBackgroundColor"
                    Value="Transparent" />
                <Setter
                    Property="TabStripPlacement"
                    Value="Bottom" />
            </Style>


        </ResourceDictionary>
    </ContentPage.Resources>

    <ContentPage.Content>
        <Grid RowDefinitions="75,30,*" RowSpacing="0" >

            <xct:TabView Grid.Row="1" x:Name="MainTabView" Grid.RowSpan="2" Style="{StaticResource CustomTabStyle}" IsSwipeEnabled="False"  SelectionChanged="TabView_SelectionChanged">
                <xct:TabView.TabStripBackgroundView>
                    <Image Source="tabview" Margin="0,0" Aspect="Fill"/>
                </xct:TabView.TabStripBackgroundView>

                <xct:TabViewItem 
                    x:Name="MyTab1"   
                    TabTapped="Tab1_TabTapped"  
                    FontFamily="FontIcons"  
                    Text="HOME" 
                    TextColor="{StaticResource DarkBlue}"
                    TextColorSelected="{StaticResource White}"
                    ControlTemplate="{StaticResource TabItemTemplate}"
                    BadgeBackgroundColor="{StaticResource LightBgColor}"
                    BadgeBackgroundColorSelected="{StaticResource DarkBlue}"
                    Padding="{OnPlatform iOS='0,10,0,0'}"
                    Icon="home.png"
                    IconSelected="home.png">
                   <views:HomeView></views:HomeView>
                </xct:TabViewItem>

                <xct:TabViewItem 
                    x:Name="MyTab3"
                    Text="TIME" 
                    ControlTemplate="{StaticResource TabItemTemplate}"
                    TextColor="{StaticResource DarkBlue}"
                    TextColorSelected="{StaticResource White}"
                    BadgeBackgroundColor="{StaticResource LightBgColor}"
                    BadgeBackgroundColorSelected="{StaticResource DarkBlue}"
                    Padding="{OnPlatform iOS='0,10,0,0'}"
                    TabTapped="Tab3_TabTapped"
                    Icon="time.png"
                    IconSelected="timeselected.png"
                    >
                    <views:TimeView  x:Name="TimeViewContent"></views:TimeView>
                </xct:TabViewItem>
            </xct:TabView>

            <!--Header-->
            <pancakeview:PancakeView Grid.RowSpan="2" CornerRadius="0,0,30,30" BackgroundColor="{StaticResource Blue}" Padding="{OnPlatform iOS='0,40,0,0'}">

                <pancakeview:PancakeView.Shadow>
                    <pancakeview:DropShadow Color="#000000"/>
                </pancakeview:PancakeView.Shadow>

                <StackLayout VerticalOptions="Center">
                  <Label HorizontalOptions="Center" TextColor="{StaticResource White}">
                        <Label.FormattedText>
                            <FormattedString>
                                <Span Text="Welcome " FontFamily="Medium" FontSize="25"/>
                                <Span Text="Christopher" FontFamily="Bold" FontSize="25"/>
                                <Span Text="!" FontFamily="Bold" FontSize="25"/>
                            </FormattedString>
                        </Label.FormattedText>
                    </Label>
                    <StackLayout Orientation="Horizontal" HorizontalOptions="Center" >
                        <Label Text="Not Christopher?" TextColor="{StaticResource White}" FontSize="14" FontFamily="Regular" />
                        <Label Text="click here" TextColor="{StaticResource White}" FontSize="14" FontFamily="Regular" TextDecorations="Underline" xct:TouchEffect.NativeAnimation="True">
                            <Label.GestureRecognizers>
                                <TapGestureRecognizer Tapped="Switch_Tapped"/>
                            </Label.GestureRecognizers>
                        </Label>
                    </StackLayout>
                </StackLayout>
            </pancakeview:PancakeView>
        </Grid>

    </ContentPage.Content>

</ContentPage>

MainPage.Xaml.cs:

  1. I tried Tab_Tapped Event

    private async void Tab3_TabTapped(object sender, Xamarin.CommunityToolkit.UI.Views.TabTappedEventArgs e)
    {
        var isUsavedChanges = await SecureStorage.GetAsync("UnsavedChanges");
        if (isUsavedChanges == "true")
        {
            DisplayMessage displayMessage = new DisplayMessage()
            {
                Description = "You have some unsaved changes on the page, Do you want to discard it?",
                Title = "Warning"
            };
            await DisplayMessage(displayMessage);
            //return;
        }            
    }
    
  • Display Message Method

    private async Task DisplayMessage(DisplayMessage displayMessage)
    {
        var customView = new ConfirmChanges();
        customView.BindingContext = this;
        await PopupNavigation.Instance.PushAsync(customView);
    }
    
  • Command to Close Popup

    [RelayCommand]
    private async void ClosePopup()
    {
        await PopupNavigation.Instance.PopAsync();
    }
    
  • Command to Discard Changes

    [RelayCommand]
    private async void DiscardEntries()
    {
        await SecureStorage.SetAsync("UnsavedChanges", "false");
         // Create a new instance of the ContentView.
        var myContentView = new TimeView();
        // Set the Content property of the ContentPage to the ContentView instance.
        MyTab3.Content=myContentView;
        //MyTab1.IsSelected = false;
        //MyTab3.IsSelected = true;
    }
    
  1. I tried TabView_SelectionChanged Event. Here I didn't implemented popup logic just wanted to test if i can use this event to hide show views.

    private async void TabView_SelectionChanged(object sender, Xamarin.CommunityToolkit.UI.Views.TabSelectionChangedEventArgs e)
    {
        var tabView = ((TabView)sender);
        if (tabView != null && tabView.SelectedIndex == 1)
        {
            MyTab2.IsSelected = false;                
            MyTab1.IsSelected = true;               
        }
    }
    
Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
Shrikant Dandile
  • 376
  • 3
  • 12
  • What is your actual problem in this? you have done it right. Use the`TabView_SelectionChanged` to check for any pending changes. Are you having issues for the logic buildup in TabView_SelectionChanged for showing confirmation(your DisplayMessage) popup? – Blu Jun 02 '23 at 08:16
  • Yes. I am not able to stop loading Tab2 view even if there is something pending on Tab1. Even if i have write MyTab2.IsSelected = false; still my Tab2 is visible on the page. – Shrikant Dandile Jun 02 '23 at 13:16

2 Answers2

0

Okay then try doing something like this, let me know if it doesn’t fits your requirements.

private async void TabView_SelectionChanging(object sender, XamForms.Controls.TabSelectionChangingEventArgs e)
{
    if (e.NewIndex == 1) // Check if the user is switching to Tab2 or alter it accordingly if you want to do it in dynamic way 
    {
        var tab1Content = myTabView.Children[0].Content; // This will get the content of Tab1

        if (tab1Content is YourTab1ContentPage tab1Page) // Replace YourTab1ContentPage with the actual type of your Tab1 content page
        {
            if (tab1Page.HasUnsavedChanges) // Check if unsaved changes exist on Tab1, you need to build your own logic or have a global boolean in your VM so that you can even access it here like YOURVM. HasUnsavedChanges

            //var isUsavedChanges = await SecureStorage.GetAsync("UnsavedChanges");
            //if (isUsavedChanges == "true")

            {
                bool userResponse = await DisplayAlert("Unsaved Changes", "You have unsaved changes on Tab1. Do you want to continue?", "Yes", "No");

                if (!userResponse)
                {
                    e.Cancel = true; // Cancel the tab switch if the user chooses not to continue
                }
            }
        }
    }
}

And for dynamic tab switch checking do it like in the way:

private void TabbedPage_SelectedIndexChanged(object sender, EventArgs e)
{
    var selectedTab = myTabbedPage.CurrentPage; // Get the currently selected TabPage

    if (selectedTab == tab1Page) // Replace tab1Page with your Tab1 ContentPage instance
    {
        // Tab1 is selected
        // Use the above code block logic here
    }
    else if (selectedTab == tab2Page) // Replace tab2Page with your Tab2 ContentPage instance
    {
        // Tab2 is selected
        // Use the above code block logic here
    }
    // Add conditions for other tabs if needed
}

Blu
  • 821
  • 4
  • 17
0

Here is the solution I used.

MainPage.xaml

 private async void TabView_SelectionChanged(object sender, Xamarin.CommunityToolkit.UI.Views.TabSelectionChangedEventArgs e)
    {
        var isUsavedChanges = await SecureStorage.GetAsync("UnsavedChanges");
            if (isUsavedChanges == "true")
            {                    
                DisplayMessage displayMessage = new DisplayMessage()
                {
                    Description = "You have some unsaved changes on the page, Do you want to discard it?",
                    Title = "Warning"

                };
                await DisplayMessage(displayMessage);
            }
            else
            {
                
                    MyTab3.Content.IsVisible = true;
                    var tabViewItem = new TabViewItem();
                    var myContentView = new TimeView();
                    tabViewItem.Content = myContentView;
                    MyTab3.Content = myContentView;                    

            }


    }

My Problem that i was not able to stop loading webview is still there but i used MyTab3.Content.IsVisible = true; so at least it will be looks like it is empty. I may be wrong but this is what i found. Then in second step i used "TabView's" SelectedIndex property to show desired view.

ConfirmMessage.Xaml - Discard Button Click:

[RelayCommand]
    private async void DiscardEntries() // this command is on MainPage.xaml.cs
    {
       
            MyTab3.Content.IsVisible = true;
            await PopupNavigation.Instance.PopAsync();

            await SecureStorage.SetAsync("UnsavedChanges", "false");
            var tabViewItem = new TabViewItem();
            // Create a new instance of the ContentView.
            var myContentView = new TimeView();
            // Set the Content property of the ContentPage to the ContentView instance.
            tabViewItem.Content = myContentView;
            MyTab3.Content = myContentView;
            var homeContent = new HomeView();
            MyTab1.Content = homeContent;
            MyTab1.IsSelected = false;
            MyTab3.IsSelected = true;
            MainTabView.SelectedIndex = 1;  // This property used to show or hide the desired view          
    }
Shrikant Dandile
  • 376
  • 3
  • 12