如何在 .Net MAUI 中重新加载或更新用户界面,当文化已经改变?

huangapple go评论115阅读模式
英文:

How to reload or update UI in .Net MAUI, when culture has been changed?

问题

我有一个带有点击事件的按钮,触发以下操作:

Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("da");
Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("da");
CultureInfo.CurrentCulture = new CultureInfo("da-DK", false);
CultureInfo.CurrentUICulture = new CultureInfo("da-DK", false);

在按钮下方,我有一个标签,其文本是在一个.resx文件中分配的值。
该解决方案有各种标签,分布在不同的页面上,都是使用.resx文件设置的。

当我点击按钮时,如何更新所有页面以切换到新的文化?

编辑:我在这里的主要问题是刷新应用程序/触发新文化。请参阅已接受的答案,了解我是如何解决这个问题的。

英文:

I have a button with a clicked event that triggers the following:

Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("da");
Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("da");
CultureInfo.CurrentCulture = new CultureInfo("da-DK", false);
CultureInfo.CurrentUICulture = new CultureInfo("da-DK", false);

Below the button, I have a Label, with the text assigned as a value in an .resx-file.
The solution has various labels, on various pages, that are all set with .resx-files.

When I click the button, how can I update all pages to switch to the new culture?

Edit: My main problem here was refreshing the app/triggering the new culture. See that accepted answer for how I solved this.

答案1

得分: 1

我不清楚您的本地化过程是什么样的,但如果它是一个标准的方式,可以在互联网上找到,而且您已经将CultureInfo设置为本地化管理器,那么您只需要重新启动应用程序:

(Application.Current as App).MainPage = new AppShell();

如果仍然存在问题,请详细说明您的问题以及您的本地化过程/解决方案。

英文:

I'm not aware of what your localization process looks like, but if it's in a standard way that can be found on the internet and you have set the CultureInfo to the localization manager, then you just need to restart the app by

        (Application.Current as App).MainPage = new AppShell();

If there is still a problem, please, just elaborate on your problem and your localization process/solution a little bit more.

答案2

得分: 1

Resetting AppShell is bad idea and may lead to numerous bugs. I've used this solution and it works great. Basically, you'd need a localization manager and a markup extension:

public class LocalizationManager : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private static readonly Lazy<LocalizationManager> _instance = new(() => new LocalizationManager());
    private LocalizationManager()
    {
        Properties.Resources.Culture = CultureInfo.CurrentUICulture;
    }
    public static LocalizationManager Instance => _instance.Value;

    public object this[string resourceKey] => Properties.Resources.ResourceManager.GetObject(resourceKey, Properties.Resources.Culture) ?? string Empty;

    public void SetCulture(CultureInfo culture)
    {
        Properties.Resources.Culture =
        CultureInfo.DefaultThreadCurrentCulture =
        CultureInfo.DefaultThreadCurrentUICulture =
        CultureInfo.CurrentCulture =
        CultureInfo.CurrentUICulture =
        culture;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(string.Empty));
    }
}
[ContentProperty(nameof(Key))]
public class LocalizationExtension : IMarkupExtension<BindingBase>
{
    public string Key { get; set; } = string.Empty;

    public BindingBase ProvideValue(IServiceProvider serviceProvider) =>
        new Binding
        {
            Mode = BindingMode.OneWay,
            Path = $"[{Key}]",
            Source = LocalizationManager.Instance,
        };

    object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider) => ProvideValue(serviceProvider);
}

Add public LocalizationManager Localize => LocalizationManager.Instance; to your model. You could do it other way, this is just an example.

Adjust your xaml like
<Label Text="{Binding Localize[SamplePage_Loading]}" /> where SamplePage_Loading is key of resource.

To change current language just call LocalizationManager.Instance.SetCulture(newCultureOfChoice);

英文:

Resetting AppShell is bad idea and may lead to numerous bugs. I've used this solution and it works great. Basically, you'd need a localization manager and a markup extension:

public class LocalizationManager : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private static readonly Lazy&lt;LocalizationManager&gt; _instance = new(()=&gt; new LocalizationManager());
    private LocalizationManager()
    {
        Properties.Resources.Culture = CultureInfo.CurrentUICulture;
    }
    public static LocalizationManager Instance =&gt; _instance.Value;

    public object this[string resourceKey] =&gt; Properties.Resources.ResourceManager.GetObject(resourceKey, Properties.Resources.Culture) ?? string.Empty;

    public void SetCulture(CultureInfo culture)
    {
        Properties.Resources.Culture =
        CultureInfo.DefaultThreadCurrentCulture=
        CultureInfo.DefaultThreadCurrentUICulture =
        CultureInfo.CurrentCulture =
        CultureInfo.CurrentUICulture =
        culture;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(string.Empty));
    }
}
[ContentProperty(nameof(Key))]
public class LocalizationExtension : IMarkupExtension&lt;BindingBase&gt;
{
    public string Key { get; set; } = string.Empty;

    public BindingBase ProvideValue(IServiceProvider serviceProvider) =&gt;
        new Binding
        {
            Mode = BindingMode.OneWay,
            Path = $&quot;[{Key}]&quot;,
            Source = LocalizationManager.Instance,
        };

    object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider) =&gt; ProvideValue(serviceProvider);
}

Add public LocalizationManager Localize =&gt; LocalizationManager.Instance; to your model. You could do it other way, this is just an example.

Adjust your xaml like
&lt;Label Text=&quot;{Binding Localize[SamplePage_Loading]}&quot; /&gt; where SamplePage_Loading is key of resource.

To change current language just call LocalizationManager.Instance.SetCulture(newCultureOfChoice);

答案3

得分: 0

I've ended up doing it this way:

首先,在代码中,一个按钮具有以下点击事件:

private void ChosenLanguageTapped(object sender, EventArgs e)
{
App.CultureString = new CultureInfo("culture-code", false);
SetUIMethod(App.CultureString);
Preferences.Set("language", App.CultureString.Name);
Reset();
}

在我的 "SetUIMethod" 中,我有以下说明:

public void SetUIMethod(CultureInfo culture)
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
}

所以新的文化已经设置好,最后,我调用 Reset(),它执行以下操作:

void Reset()
{
(Application.Current as App).MainPage.Dispatcher.Dispatch(() =>
{
(Application.Current as App).MainPage = new AppShell();
});
}

我会在某个时候查看 Serge Misnik 的答案,但目前这样就可以了。

关于在关闭并重新打开应用程序时保留语言,我使用了 Gerald Versluis 的指南这里

英文:

I've ended up doing it this way:

First, a button has the folllowing Clicked-event in the code-behind:

private void ChosenLanguageTapped(object sender, EventArgs e)
{
    App.CultureString = new CultureInfo(&quot;culture-code&quot;, false);
    SetUIMethod(App.CultureString);
    Preferences.Set(&quot;language&quot;, App.CultureString.Name);
    Reset();
}

In my "SetUIMethod", I have the following instructions:

    public void SetUIMethod(CultureInfo culture)
{
    Thread.CurrentThread.CurrentCulture = culture;
    Thread.CurrentThread.CurrentUICulture = culture;
    CultureInfo.DefaultThreadCurrentCulture = culture;
    CultureInfo.DefaultThreadCurrentUICulture = culture;
}

So the new culture is set, and lastly, I call Reset(), which does the following:

void Reset()
{
    (Application.Current as App).MainPage.Dispatcher.Dispatch(() =&gt;
    {
        (Application.Current as App).MainPage = new AppShell();
    });
}

I will look into Serge Misnik's answer at some point, but this is fine for now.

In regards to keeping language when the app is closed and re-opened, I used Gerald Versluis' guide here

答案4

得分: 0

使用在Dispatcher.Dispatch方法中设置文化的方法在我的MAUI应用程序中对我有所帮助。在dispatcher方法内部设置新的AppShell使应用程序完全卡住。

App.Current.MainPage = new AppShell();
(Application.Current as App).MainPage.Dispatcher.Dispatch(() =>
{
    CultureInfo cultureInfo = new CultureInfo(culture, false);
    CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
    CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
    Thread.CurrentThread.CurrentCulture = cultureInfo;
    Thread.CurrentThread.CurrentUICulture = cultureInfo;
});
英文:

The approach with setup Cultures within Dispatcher.Dispatch method helped me in my MAUI app. Setup new AppShell inside dispatcher method made the app completely stuck.

App.Current.MainPage = new AppShell();
(Application.Current as App).MainPage.Dispatcher.Dispatch(() =&gt;
{
    CultureInfo cultureInfo = new(culture, false);
    CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
    CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
    Thread.CurrentThread.CurrentCulture = cultureInfo;
    Thread.CurrentThread.CurrentUICulture = cultureInfo;
});

huangapple
  • 本文由 发表于 2023年6月26日 18:19:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76555754.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定