Xamarin.Forms: Reload a contentpage contained in a tabbedpage to update the data

Marcel Delhaye 26 Reputation points
2022-05-15T18:00:25.237+00:00

Hello,
The default language of my Xamarin.Forms app for Android is French. I would like the user to be able to change the language and choose English or Spanish. To do this, I added 3 resource files: AppResources.resx, AppResources.en.resx, and AppResources.es.resx to a Resx folder. In these files, I filled in the keywords to be translated.
Here is the beginning of the xaml code of the page to be translated:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:syncfusion="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
             xmlns:sync="clr-namespace:Syncfusion.XForms.Buttons;assembly=Syncfusion.Buttons.XForms"
             xmlns:resx="clr-namespace:MemoCourses.Resx"
             mc:Ignorable="d"
             x:Class="MemoCourses.Views.ParametreDestPage"
             Title="{x:Static resx:AppResources.ParamDest_Titre}">


    <ContentPage.Content>

        <StackLayout>

            <syncfusion:SfListView  x:Name="ParametreListView"
                                    Margin="15,10,15,0"
                                    HeightRequest="40"
                                    DragStartMode="None"
                                    SelectionMode="None"
                                    IsScrollBarVisible="False"
                                    ItemSize="60">

                <syncfusion:SfListView.DragDropController>
                    <syncfusion:DragDropController UpdateSource="True"/>
                </syncfusion:SfListView.DragDropController>

                <!--Built in Cells-->
                <syncfusion:SfListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid Padding="10">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="30*" />
                                    <ColumnDefinition Width="6*" />
                                </Grid.ColumnDefinitions>

                                <Label Text="{x:Static resx:AppResources.ParamDest_L1}"
                                   FontSize="16" 
                                   TextColor="Black" 
                                   Margin="0,-20,0,0"
                                   VerticalTextAlignment="Center"
                                   FontAttributes="None"
                                   Grid.Column="0"/>
                                <Switch HorizontalOptions="Center"
                                    Margin="0,-20,0,0"
                                    VerticalOptions="Center"
                                    IsToggled="{Binding HelpScreensEnabled}" 
                                    Toggled="Switch_Toggled"
                                    Grid.Column="1" />
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </syncfusion:SfListView.ItemTemplate>
            </syncfusion:SfListView>

            <syncfusion:SfListView  x:Name="ScreenLockListView"
                                    Margin="15,10,15,0"
                                    HeightRequest="40"
                                    DragStartMode="None"
                                    SelectionMode="None"
                                    IsScrollBarVisible="False"
                                    ItemSize="60">

                <syncfusion:SfListView.DragDropController>
                    <syncfusion:DragDropController UpdateSource="True"/>
                </syncfusion:SfListView.DragDropController>

                <!--Built in Cells-->
                <syncfusion:SfListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid Padding="10">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="30*" />
                                    <ColumnDefinition Width="6*" />
                                </Grid.ColumnDefinitions>

                                <Label Text="{x:Static resx:AppResources.ParamDest_L2}" 
                                   FontSize="16" 
                                   TextColor="Black" 
                                   Margin="0,-20,0,0"
                                   VerticalTextAlignment="Center"
                                   FontAttributes="None"
                                   Grid.Column="0"/>
                                <Switch HorizontalOptions="Center"
                                    Margin="0,-20,0,0"
                                    VerticalOptions="Center"
                                    IsToggled="{Binding AutoScreenLockEnabled}" 
                                    Toggled="SwitchScreenLock_Toggled"
                                    Grid.Column="1" />
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </syncfusion:SfListView.ItemTemplate>
            </syncfusion:SfListView>

            <syncfusion:SfListView  x:Name="PanierLockListView"
                                    Margin="15,10,15,0"
                                    HeightRequest="40"
                                    DragStartMode="None"
                                    SelectionMode="None"
                                    IsScrollBarVisible="False"
                                    ItemSize="60">

                <syncfusion:SfListView.DragDropController>
                    <syncfusion:DragDropController UpdateSource="True"/>
                </syncfusion:SfListView.DragDropController>

                <!--BackgroundColor="AntiqueWhite"-->

                <!--Built in Cells-->
                <syncfusion:SfListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid Padding="10">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="30*" />
                                    <ColumnDefinition Width="6*" />
                                </Grid.ColumnDefinitions>

                                <Label Text="{x:Static resx:AppResources.ParamDest_L3}"
                                   FontSize="16" 
                                   TextColor="Black" 
                                   Margin="0,-20,0,0"
                                   VerticalTextAlignment="Center"
                                   FontAttributes="None"
                                   Grid.Column="0"/>
                                <Switch HorizontalOptions="Center"
                                    Margin="0,-20,0,0"
                                    VerticalOptions="Center"
                                    IsToggled="{Binding PanierLocked}" 
                                    Toggled="SwitchPanierLock_Toggled"
                                    Grid.Column="1" />
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </syncfusion:SfListView.ItemTemplate>
            </syncfusion:SfListView>


            <sync:SfRadioGroup x:Name="radioGroup" Margin="10,30,10,0" >
                <Label x:Name="textsize" 
                       Text="{x:Static resx:AppResources.ParamDest_L4}" 
                       Margin="15,0,0,0" 
                       VerticalOptions="Start" 
                       HorizontalOptions="Start" 
                       FontSize="16" 
                       TextColor="#000000">
                </Label>
                <sync:SfRadioButton x:Name="rbtnSuperGreat" 
                                    Margin="20,15,0,0" 
                                    Text="{x:Static resx:AppResources.ParamDest_L5}" 
                                    FontSize="17"
                                    TextColor="#000000" 
                                    StateChanged="rbtnSuperGreat_StateChanged" >
                </sync:SfRadioButton>
                <sync:SfRadioButton x:Name="rbtnGreat" 
                                    Margin="20,15,0,0" 
                                    Text="{x:Static resx:AppResources.ParamDest_L6}" 
                                    FontSize="17"
                                    TextColor="#000000" 
                                    IsChecked="True"
                                    StateChanged="rbtnGreat_StateChanged" >
                </sync:SfRadioButton>
                <sync:SfRadioButton x:Name="rbtnMedium" 
                                    Margin="20,15,0,0" 
                                    Text="{x:Static resx:AppResources.ParamDest_L7}" 
                                    FontSize="16" 
                                    TextColor="#000000"  StateChanged="rbtnMedium_StateChanged" >
                </sync:SfRadioButton>
                <sync:SfRadioButton x:Name="rbtnSmall" 
                                    Margin="20,15,0,0" 
                                    Text="{x:Static resx:AppResources.ParamDest_L8}" 
                                    FontSize="14" 
                                    TextColor="#000000"  StateChanged="rbtnSmall_StateChanged" >
                </sync:SfRadioButton>
            </sync:SfRadioGroup>


            <Label x:Name="langue" 
                       Text="{x:Static resx:AppResources.ParamDest_L9}" 
                       Margin="25,25,0,0" 
                       VerticalOptions="Start" 
                       HorizontalOptions="Start" 
                       FontSize="16" 
                       TextColor="#000000">
            </Label>

            <Picker x:Name="picker"
                SelectedIndexChanged="picker_SelectedIndexChanged"
                Margin="20,0,20,0">
                <Picker.Items>
                    <x:String>Default</x:String>
                    <x:String>English</x:String>
                    <x:String>Español</x:String>
                </Picker.Items>
            </Picker>

        </StackLayout>







    </ContentPage.Content>

</ContentPage>

And the corresponding cs code :

using System;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using MemoCourses.Models;
using MemoCourses.ViewModels;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Threading;
using MemoCourses.Resx;

namespace MemoCourses.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ParametreDestPage : ContentPage
    {
        ObservableCollection<Parametre> DB_ParametreList = new ObservableCollection<Parametre>();
        ReadAllParametreList dbparametre = new ReadAllParametreList();
        ObservableCollection<Panier> DB_PanierList = new ObservableCollection<Kit>();
        ReadAllPanierList dbpanier = new ReadAllPanierList();
        //
        Parameter parameters;
        // ===

        public ParametreDestPage()
        {
            InitializeComponent();
            string language = Thread.CurrentThread.CurrentUICulture.Name;
            picker. SelectedIndex = language == "es" ? 2 : language == "en" ? 1 : 0;
        }
…
private void picker_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (App.SelectedIndex == picker. SelectedIndex)
                return;
            App.SelectedIndex = picker. SelectedIndex;
            CultureInfo language = new CultureInfo(picker. SelectedIndex == 0 ? "" : picker. SelectedIndex == 1 ? "en" : "es");
            Thread.CurrentThread.CurrentUICulture = language;
            AppResources.Culture = language;
            Application.Current.MainPage = new NavigationPage(new ParametreDestPage());
        }
    }
}

Everything works except that this contentpage is part of a tabbedpage, and when I reload the page with the code:

Application.Current.MainPage = new NavigationPage(new ParametreDestPage());

... the title bar and tabs are no longer displayed. The user can no longer go back or access the menu.
To complete the information in my code, here is the xaml page of the tabbedpage:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:d="http://xamarin.com/schemas/2014/forms/design"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:MemoCourses.Views"
            mc:Ignorable="d"
            BarBackgroundColor="DarkOliveGreen"
            BarTextColor="White"
            SelectedTabColor="White"
            Title="{x:Static resx:AppResources. ParamPage_Titre}"
            x:Class="MemoCourses.Views.ParametrePage">
    <local:ParametreDestPage />
    <local:ParametreVersionsPage />

</TabbedPage>

How do I apply the changes (refresh the data) to the ParametreDestPage by leaving the title, tabs and the menu button visible?
Thank you very much for your help.

Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,294 questions
0 comments No comments
{count} votes

Accepted answer
  1. Wenyan Zhang (Shanghai Wicresoft Co,.Ltd.) 26,316 Reputation points Microsoft Vendor
    2022-05-16T08:51:30.933+00:00

    Hi @Marcel Delhaye ,

    the title bar and tabs are no longer displayed. The user can no longer go back or access the menu.

    Because you set the initial page for the app as a NavigationPage, try to check what is MainPage in App class. From your description, it may be ParametrePage. Replace Application.Current.MainPage = new NavigationPage(new ParametreDestPage());
    by Application.Current.MainPage = new ParametrePage();
    For more information about TabbedPage, refer to https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/tabbed-page

    How do I apply the changes (refresh the data) to the ParametreDestPage by leaving the title, tabs and the menu button visible?

    You need to add value to the resx:AppResources file, you want to support three language, so you need to create three resx file, and add the translation value. The translation file uses the same Name values specified in the default file but contains different language strings in the Value column. From your Xaml file of your ParametreDestPage, I can see that there is no element in the ContentPage. I add a label for testing, you could refer to the following code:
    Xaml

    <?xml version="1.0" encoding="utf-8" ?>  
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"  
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"  
                 x:Class="TransTabPageDemo.ParametreDestPage"  
                 xmlns:resx="clr-namespace:TransTabPageDemo.Resx"  
                 Title="{x:Static resx:Resources.AddButton}">  
        <ContentPage.Content>  
            <StackLayout>  
                <Label Text="{x:Static resx:Resources.WelcomeLabel}"  
                    VerticalOptions="CenterAndExpand"   
                    HorizontalOptions="CenterAndExpand" />  
                  
                <Picker SelectedIndexChanged ="Picker_SelectedIndexChanged">  
                    <Picker.Items>  
                        <x:String>1</x:String>  
                        <x:String>2</x:String>  
                        <x:String>3</x:String>  
                    </Picker.Items>  
                </Picker>  
            </StackLayout>  
        </ContentPage.Content>  
    </ContentPage>  
    

    PickEvent

     private void Picker_SelectedIndexChanged(object sender, EventArgs e)  
            {  
                Picker picker = (Picker)sender;  
                CultureInfo language = new CultureInfo(picker.SelectedIndex == 0 ? "fr" : picker.SelectedIndex == 1 ? "en" : "es");  
                Thread.CurrentThread.CurrentUICulture = language;  
                AppResources.Culture = language;  
                Application.Current.MainPage = new ParametrePage();  
      
            }  
    

    In my Resources.es.resx, the Name is WelcomeLabel , Valve is ¡Bienvenido a Xamarin.Forms!
    For more details, refer to https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/localization/text?pivots=windows#create-resx-files

    In addition, On Android, the language settings are detected and cached when the application starts. If you change languages, you may need to exit and restart the application to see the changes applied.

    ---------UPDATE--------
    If you want to improve Runtime Changes, refer to this blog :https://devblogs.microsoft.com/xamarin/mastering-multilingual-in-xamarin-forms/
    **LocalizationResourceManager **

     public class LocalizationResourceManager : INotifyPropertyChanged  
        {  
            public static LocalizationResourceManager Instance { get; } = new LocalizationResourceManager();  
      
            public string this[string text]  
            {  
                get  
                {  
                    return AppResources.ResourceManager.GetString(text, AppResources.Culture);  
                }  
            }  
      
            public void SetCulture(CultureInfo language)  
            {  
                Thread.CurrentThread.CurrentUICulture = language;  
                AppResources.Culture = language;  
      
                Invalidate();  
            }  
      
            public event PropertyChangedEventHandler PropertyChanged;  
      
            public void Invalidate()  
            {  
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));  
            }  
        }  
    

    Helper

     [ContentProperty("Text")]  
        public class TranslateExtension : IMarkupExtension<BindingBase>  
        {  
            public string Text { get; set; }  
            public string StringFormat { get; set; }  
            object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)  
            {  
                return ProvideValue(serviceProvider);  
            }  
      
            public BindingBase ProvideValue(IServiceProvider serviceProvider)  
            {  
                var binding = new Binding  
                {  
                    Mode = BindingMode.OneWay,  
                    Path = $"[{Text}]",  
                    Source = LocalizationResourceManager.Instance,  
                    StringFormat = StringFormat  
      
                };  
                return binding;  
            }  
        }  
    

    Best Regards,
    Wenyan Zhang


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Marcel Delhaye 26 Reputation points
    2022-05-22T17:16:06.607+00:00

    I thought everything worked well thanks to the LocalizationResourceManager, but I hadn't seen that the menu items didn't change languages, unlike all the other pages. For the items to be translated, you have to relaunch the app, or put it in the background, then return to the app.
    Here is the xaml code of the menu page:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:d="http://xamarin.com/schemas/2014/forms/design"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 mc:Ignorable="d"
                 x:Class="MemoCourses.Views.MenuPage"
                 xmlns:helpers="clr-namespace:MemoCourses.Helpers"
                 Title="{helpers:Translate MenuPage_Titre}">
    
        <StackLayout VerticalOptions="FillAndExpand" >
            <Image Source="logo.png"
                   VerticalOptions="FillAndExpand"
                   HorizontalOptions="FillAndExpand"/>
    
            <ListView x:Name="ListViewMenu"
                      SeparatorVisibility="None"
                      HasUnevenRows="True">
    
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout Orientation="Vertical" VerticalOptions="Fill">
                                <StackLayout Orientation="Horizontal" >
                                    <Image Source="{Binding IconFileName}" 
                                           Margin="10,10,0,10"/>
    
                                    <Label Text="{Binding Title}" d:Text="{Binding .}" 
                                           Margin="20,10,0,10"
                                           FontSize="Small"  
                                           TextColor="Black"
                                           BackgroundColor="Transparent"
                                           VerticalTextAlignment="Center"
                                           FontAttributes="None" />
                                </StackLayout>
                                <BoxView HeightRequest="1" 
                                         Color="LightGray" 
                                         IsVisible="{Binding IsSeparator}" />
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
    
    </ContentPage>
    

    And the code behind :

    using MemoCourses.Models;
    using MemoCourses.Resx;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using Xamarin.Forms;
    using Xamarin.Forms.Xaml;
    
    namespace MemoCourses.Views
    {
        // Learn more about making custom code visible in the Xamarin.Forms previewer
        // by visiting https://aka.ms/xamarinforms-previewer
        [DesignTimeVisible(false)]
        public partial class MenuPage : ContentPage
        {
            MainPage RootPage { get => Application.Current.MainPage as MainPage; }
            List<HomeMenuItem> menuItems;
            ViewCell lastCell;
            // bool IsSeparator = false;
            public MenuPage()
            {
                InitializeComponent();
    
                App.CatFilter = "Tout";
    
                menuItems = new List<HomeMenuItem>
                {
                    //new HomeMenuItem {Id = MenuItemType.Browse, Title="Browse", IconFileName="listes.png" },
                    new HomeMenuItem {Id = MenuItemType.Listes, Title=AppResources.MenuPage_Item_1, IconFileName="listes.png", IsSeparator=false },
                    new HomeMenuItem {Id = MenuItemType.Favoris, Title="Favoris", IconFileName="favoris.png", IsSeparator=false },
                    new HomeMenuItem {Id = MenuItemType.Articles, Title="Articles", IconFileName="articles.png", IsSeparator=false },
                    new HomeMenuItem {Id = MenuItemType.Categories, Title="Catégories", IconFileName="categories.png", IsSeparator=false },
                    new HomeMenuItem {Id = MenuItemType.Tri_des_categories, Title="Tri des catégories", IconFileName="tri_categories.png", IsSeparator=false },
                    new HomeMenuItem {Id = MenuItemType.Choix_des_categories, Title="Choix des catégories", IconFileName="choix_categories.png", IsSeparator=false },
                    new HomeMenuItem {Id = MenuItemType.Unites_mesure, Title="Unités de mesure", IconFileName="unites_mesure.png", IsSeparator=false },
                    new HomeMenuItem {Id = MenuItemType.Destinataires, Title="Destinataires", IconFileName="destinataires.png", IsSeparator=true },
                    new HomeMenuItem {Id = MenuItemType.Backup_Restore, Title="Sauvegarder / Restaurer", IconFileName="backup_restore.png", IsSeparator=false },
                    new HomeMenuItem {Id = MenuItemType.FidelityCard, Title="Cartes de fidélité", IconFileName="Fidelity_card.png", IsSeparator=false },
                    new HomeMenuItem {Id = MenuItemType.Aide, Title="Aide", IconFileName="aide.png", IsSeparator=true },
                    new HomeMenuItem {Id = MenuItemType.Parametres, Title="Paramètres", IconFileName="parametres.png", IsSeparator=false},
                    new HomeMenuItem {Id = MenuItemType.About, Title="A propos", IconFileName="about.png", IsSeparator=false }
    
                };
    
                ListViewMenu.ItemsSource = menuItems;
    
                ListViewMenu.SelectedItem = menuItems[0];
                ListViewMenu.ItemSelected += async (sender, e) =>
                {
                    if (e.SelectedItem == null)
                        return;
    
                    var id = (int)((HomeMenuItem)e.SelectedItem).Id;
                    await RootPage.NavigateFromMenu(id);
                };
            }
    
            private void ViewCell_Tapped(object sender, EventArgs e)
            {
                if (lastCell != null)
                    lastCell.View.BackgroundColor = Color.Transparent;
                var viewCell = (ViewCell)sender;
                if (viewCell.View != null)
                {
                    viewCell.View.BackgroundColor = Color.Transparent;
                    lastCell = viewCell;
                }
            }
        }
    }
    

    What should I do to make changes on running? Thank you for your help.