在xaml页面上的xamarin应用程序中,我正在使用xaml扩展加载本地化字符串(详细信息描述为here)。举例来说:
<Label Text={i18n:Translate Label_Text}/>
字符串
现在,我希望用户能够在运行时更改应用程序的语言(使用选择器)。如果发生这种情况,我想立即改变语言。
我可以以某种方式重新加载所有翻译文本吗?
我可以删除所有页面并重新创建它们,但我正在努力避免这种情况。
我还可以将所有本地化文本绑定到页面模型中的字符串。但是对于真正的静态字符串来说,这是很多不必要的代码。
2条答案
按热度按时间d4so4syb1#
不幸的是,您不能强制使用 XAML 中的标记扩展设置的控件使用这些扩展重新评估其属性-评估仅在解析 XAML 文件时完成一次。基本上在幕后发生的事情是这样的:
1.您的扩展已示例化
1.在创建的示例上调用
ProvideValue
方法,并在目标控件上使用返回值1.对创建的示例的引用没有被存储(或者是一个弱引用,我不确定),所以您的扩展已经为GC做好了准备
您可以通过定义终结器(描述器)并在其中设置断点来确认扩展只使用一次。它会在页面加载后很快被命中(至少在我的情况下是这样的--你可能需要显式地调用
GC.Collect()
)。所以我认为问题很明显-您不能在任意时间再次调用扩展上的ProvideValue
,因为它可能不再存在。但是,有一个解决方案可以解决您的问题,甚至不需要对 XAML 文件进行任何更改-您只需要修改
TranslateExtension
类。这个想法是,在引擎盖下,它将设置正确的绑定,而不是简单地返回一个值。首先,我们需要一个类作为所有绑定的源(我们将使用单例设计模式):
字符串
这里的目标是
Translator.Instance["Label_Text"]
应该返回当前扩展为"Label_Text"
返回的转换。然后扩展应该在ProvideValue
方法中设置绑定:型
现在,您需要做的就是在每次更改语言时调用
Translator.Instance.Invalidate()
。请注意,使用
{i18n:Translate Label_Text}
将等同于使用{Binding [Label_Text], Source={x:Static i18n:Translator.Instance}}
,但更简洁,并节省了修改 XAML 文件的工作。q3aa05252#
我尝试过实现@Grx70提出的伟大解决方案,但示例中使用的一些类和属性是Xamarin内部的,所以不能以这种方式使用。不过,根据他们的最后一条评论,这是让它工作的线索,虽然不像最初提出的那样优雅,我们可以这样做:
字符串
这是最初提出的Translator类,但为了清楚起见,在这里用GetString调用进行了复制:
型
然后,正如最初的帖子所建议的那样,而不是用以下内容绑定文本:
型
绑定
型
我会在项目结束时(添加多种语言)点击这个按钮,但是使用Visual Studio Community和Search/Replace with RegEx,可以在整个项目中替换绑定,替换:
型
与:
型
注意:Regex假设原始Translate宏的命名空间为'resources',而Translator类的命名空间为'core',您可能需要进行适当的更新。我很感激这是对@Grx70的其他伟大解决方案的一个小调整(我站在巨人的肩膀上),但我在这里发布这个,因为任何人都有同样的问题。