C# 在Xamarin值转换器中使用文本字符串作为绑定参数
我在我的Xamarin项目中经常使用IvalueConverter。我希望使用任意文本字符串作为绑定参数,而不必绑定到视图或ViewModel上的属性。我经常发现自己不得不在视图模型上创建我认为是任意/多余的属性,只是为了支持我想要的功能,这会使我的代码变得混乱。这种情况的用例是使用转换器从自定义XML文件中获取翻译后的字符串。(在我的项目中,我不能使用标准的resx文件i18n方法-我需要遍历一个XML文件来找到我需要的字符串) 我希望在Xaml中执行此操作:C# 在Xamarin值转换器中使用文本字符串作为绑定参数,c#,xaml,xamarin,C#,Xaml,Xamarin,我在我的Xamarin项目中经常使用IvalueConverter。我希望使用任意文本字符串作为绑定参数,而不必绑定到视图或ViewModel上的属性。我经常发现自己不得不在视图模型上创建我认为是任意/多余的属性,只是为了支持我想要的功能,这会使我的代码变得混乱。这种情况的用例是使用转换器从自定义XML文件中获取翻译后的字符串。(在我的项目中,我不能使用标准的resx文件i18n方法-我需要遍历一个XML文件来找到我需要的字符串) 我希望在Xaml中执行此操作: <Label Text="
<Label Text="{Binding 'my-awesome-string-of-text',
Converter={StaticResource ConvertMyStringToSomethingElseConvertor}}"/>
我想做什么?对于包含大量不同可翻译字符串的页面,ViewModel很快就会变得杂乱无章。这是可以做到的,但并非完全如此。您需要具有名称空间前缀,以便最终执行与转换器类似的操作。看看这个插件,github上的多语言插件。当然没有约束力。绑定用于绑定,而不是以任意方式运行任意代码。EDIT!这可以通过IMarkupExtension完成! 它已在中实现,用于从中的RESX文件中获取已翻译的字符串。我已经调整了他们的方法,从我的自定义翻译XML文件中提取并绑定到该文件,如下所示:
[ContentProperty(nameof(Text))]
public class TranslateExtension : IMarkupExtension<BindingBase>
{
public string Text { get; set; }
public string StringFormat { get; set; }
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider) => ProvideValue(serviceProvider);
public BindingBase ProvideValue(IServiceProvider serviceProvider)
{
#if !NETSTANDARD1_0
var t = MyCustomTranslationsHolder.Get(Text);
var binding = new Binding
{
Mode = BindingMode.OneTime,
Path = $"text",
Source = new {text = !string.IsNullOrEmpty(t) ? t : Text},
StringFormat = StringFormat
};
return binding;
#else
throw new NotSupportedException("Translate XAML MarkupExtension is not supported on .NET Standard 1.0");
#endif
}
}
```
如果调试成功,则显示的字符串将是翻译字符串,如果调试失败,则显示的字符串将是资源字符串
原始答案,为子孙后代
对于安德鲁在评论中的建议,我找到了一个可以接受的答案
基本上,我创建了一个名为translations的静态类,并按照我的应用程序获取翻译的方式将静态属性设置为翻译的值
namespace MyApp.Utilities
{
private static string _myAwesomeString;
public static string MyAwesomeString
{
get
{
if (string.IsNullOrEmpty(_myAwesomeString))
{
MyAwesomeString= GetTranslation("MyAwesomeResource");
}
return _myAwesomeString;
}
private set => _myAwesomeString = value;
}
}
然后在xaml中引用,如下所示:
<Label Text="{x:Static utils:Translations.MyAwesomeString}"></Label>
使用get/set访问器可以确保GetTranslation调用只运行一次,从而有效地让我能够像内存字典一样高效地访问跨多个屏幕使用的资源
我仍然需要在一个类中实际拥有属性,这并不理想——但至少这样,它们都在一个地方,并且不会扰乱viewmodels。如果有人知道我不需要保留实际属性的解决方案,请让我知道 谢谢你,伊万。这个插件看起来很棒,但是因为我继承了代码库,我必须为我的可翻译字符串支持自定义XML资源文件结构,而不是标准的resx,所以我认为它在这里不起作用。也许我可以用叉子或灵感来处理我的自定义文件。@AdamDiament,是的,我的答案与此相关,你需要做一些类似的事情,你可以看到他们的代码并从那里开始。也许可以使用标记扩展来获得功能。@Andrew我一直在玩弄它,但什么也做不到实际上插件就是这样做的。多语言,如果你读了我的答案,一切都指向这一点……这很酷,谢谢Ivan。很高兴我想出了一个类似于受人尊敬的插件的东西,让我相信这是一个很好的解决方案。我想我的答案会让人们找到一个比阅读插件源代码更容易的解决方案,所以我不会让你的答案成为公认的答案,但我会投赞成票!很高兴我能为你指出正确的方向。您是否确认此功能按预期工作?让我担心的是在if中设置public
MyAwesomeString
,然后返回private\u MyAwesomeString
。虽然它“应该”工作,因为私有setter“应该”在getter中的返回之前被调用,但是在if中设置\u myAwesomeString=GetTranslation()
似乎更有意义。不过我可能错了,请确保彻底测试它。谢谢@Andrew-我已经完全删除了setter,只是按照您的建议直接设置了私有变量-我现在也使用了helper方法将它简化为一行```公共静态字符串MyAwesomeString=>GetTranslation(未检测到的引用,“MyAwesomeResource”)``
Text="{converters:Translate 'The.Particular.Resource.Key'}"
namespace MyApp.Utilities
{
private static string _myAwesomeString;
public static string MyAwesomeString
{
get
{
if (string.IsNullOrEmpty(_myAwesomeString))
{
MyAwesomeString= GetTranslation("MyAwesomeResource");
}
return _myAwesomeString;
}
private set => _myAwesomeString = value;
}
}
<Label Text="{x:Static utils:Translations.MyAwesomeString}"></Label>