question

MarcelDelhaye-5524 avatar image
0 Votes"
MarcelDelhaye-5524 asked WenyanZhang-MSFT commented

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

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.






dotnet-xamarin
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

WenyanZhang-MSFT avatar image
1 Vote"
WenyanZhang-MSFT answered WenyanZhang-MSFT commented

Hi @MarcelDelhaye-5524 ,

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://docs.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://docs.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.

· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hello WenyanZhang, I would first like to say that the xaml code of the Page ParameterPage was not complete: I had copied only the part concocted by the change of language. I corrected and copied the complete code.
Next, I would like to clarify that the ParametreDestPage page is not the MainPage of my app, it is called when the user clicks on the item in a HamburgerMenu. I tried to make the proposed replacement, but it's even worse: the page appears without a title bar. I formulate my question once again: when the user chooses another language by means of the Picker, I would like the new language to be applied to the texts (this works correctly in my app), but what is essential is that the user can still have access to the HamburgerMenu to continue his work in the new language. Thank you for your help.

0 Votes 0 ·

The app will start with a new page, whatever Application.Current.MainPage = new ParametrePage(); or Application.Current.MainPage = new AppShell(); or any other page. You want to make changes on running, right? You could refer to this blog, it's a little old but still useful.

Try to create a LocalizationResourceManager class that handles language changes, and force the property to change translation.

1 Vote 1 ·

OK, I managed to modify the app to take into account the change of language, thanks to the explanations given on the blog mastering-multilingual-in-xamarin-forms
I obviously had to modify it to adapt it to my app, and correct some small errors by following the example MasteringMultilingualSample
The only solution is therefore as you suggest to create a LocalizationResourceManager class. Can you put that in a second answer, which I will accept as a definitive answer?
Thank you very much for your help in helping me solve this problem.


0 Votes 0 ·
Show more comments
MarcelDelhaye-5524 avatar image
0 Votes"
MarcelDelhaye-5524 answered WenyanZhang-MSFT commented

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.


· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

It can't be translated because the title has been set for an actual value in this way. I'm not sure if the title can be converted then translate this title, I'm still researching, I will update as soon as possible.


0 Votes 0 ·

Hello WenyanZhang, It might be easier to create a new question: Xamarin.Forms Translate items from a hamburger menu while the program is running. What do you think?

0 Votes 0 ·

Sure, you can post it as another question, and we can focus on the new thread.

0 Votes 0 ·