ResourceDictionary 源绑定到模块(用于本地化)
我有一个 XAML 窗口,其中有一组绑定到对象的字符串,如下所示:
<Label Content="{StaticResource LabelUserName}" HorizontalAlignment="Right" Name="Label1" VerticalAlignment="Center" />
当我像这样定义 ResouceDictionary 时,此代码可以正常工作:
<Window.Resources>
<ResourceDictionary >
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Strings/Strings_en-US.xaml" />
</ResourceDictionary.MergedDictionaries>
<ObjectDataProvider x:Key="objLogon" ObjectType="{x:Type StarUtilities:Logon}" />
</ResourceDictionary>
</Window.Resources>
但是,我希望能够更改字符串的绑定位置,因此我创建了一个模块如下所示:
Public Module LocalizationChooser
Public ReadOnly Property GetLocalization As Uri
Get
Return New Uri("/Strings/Strings_en-US.xaml", UriKind.Relative)
End Get
End Property
End Module
然后我决定尝试将 Source
更改为绑定字符串。但是,我尝试了以下方法,但没有任何效果:
<ResourceDictionary Source="{Binding Source={x:Static Member=StarUI:LocalizationChooser.GetLocalization}}" />
<ResourceDictionary Source="{x:Static Member=StarUI:LocalizationChooser.GetLocalization}" />
<ResourceDictionary Source="{Binding Source=StarUI:LocalizationChooser.GetLocalization}" />
<ResourceDictionary Source="{Binding Source=LocalizationChooser, Path=GetLocalization}" />
<ResourceDictionary Source="{Binding Source=StarUI:LocalizationChooser, Path=GetLocalization}" />
<ResourceDictionary Source="{Binding Source={x:Static Member=StarUI:LocalizationChooser.GetLocalization}, Path=GetLocalization}" />
<ResourceDictionary Source="{Binding Source={x:Static Member=StarUI:LocalizationChooser.GetLocalization}, Path=LocalizationChooser.GetLocalization}" />
<ResourceDictionary Source="{Binding Source={x:Static Member=StarUI:LocalizationChooser.GetLocalization}, Path=StarUI:LocalizationChooser.GetLocalization}" />
所有方法都会生成相同的错误:
“ResourceDictionary”引发了 ArgumentNullException:值不能为 null。
参数名称:item
我该怎么做才能使其正常工作?
我应该提到 StarUI 命名空间已定义如下:
xmlns:StarUI="clr-namespace:StarUI"
编辑:
我发现,通过对模块所做的更改,如果使用以下命令,我可以编译和运行代码:
<ResourceDictionary Source="{x:Static StarUI:LocalizationChooser.GetLocalization}" />
但是,我仍然没有设计时支持。由于模块返回一个不需要查找任何内容的静态项,有没有办法在这里获得设计时支持?如果没有,是否有办法在 XAML 中指定设计时的静态引用,然后为运行时指定动态引用?
编辑2:
我最终所做的是编写静态指定 Source
的 XAML,然后将构造函数设置为“覆盖”它。由于具有相同名称的字典条目将根据最后添加的字典条目进行引用,因此我可以在运行时添加字典,但在设计时仍然有字典。
我使用以下内容来简单地本地化我的代码,包括设计时支持和启用语言的动态更改。
在我的 XAML 中,我包括:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary x:Name="LocalizationStrings" Source="/Strings/Strings_en-US.xaml" />
</ResourceDictionary.MergedDictionaries>
<ObjectDataProvider x:Key="objLogon" ObjectType="{x:Type StarUtilities:Logon}" />
</ResourceDictionary>
</Window.Resources>
在我的代码隐藏中:
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.Resources.MergedDictionaries.Add(GetLocalization)
End Sub
GetLocation 位于公共模块中:
Public ReadOnly Property GetLocalization As ResourceDictionary
Get
Dim resourceLocalization As New ResourceDictionary
resourceLocalization.Source = New Uri("/Strings/Strings_zh-cn.xaml", UriKind.Relative)
Return resourceLocalization
End Get
End Property
我的 ResourceDictionary XAML 的示例是:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="ButtonLogon">Logon</sys:String>
<sys:String x:Key="ButtonCancel">Cancel</sys:String>
<sys:String x:Key="LabelUserName">User Name:</sys:String>
<sys:String x:Key="LabelPassword">Password:</sys:String>
<sys:String x:Key="LabelKey">Decryption Key:</sys:String>
</ResourceDictionary>
然后我只需通过以下方式访问语言字符串:
<Label Content="{DynamicResource LabelUserName}" Name="Label1" />
现在一切都很好!
I have a XAML Window that has a set of strings that are bound to objects like so:
<Label Content="{StaticResource LabelUserName}" HorizontalAlignment="Right" Name="Label1" VerticalAlignment="Center" />
This code works fine when I define my ResouceDictionary like this:
<Window.Resources>
<ResourceDictionary >
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Strings/Strings_en-US.xaml" />
</ResourceDictionary.MergedDictionaries>
<ObjectDataProvider x:Key="objLogon" ObjectType="{x:Type StarUtilities:Logon}" />
</ResourceDictionary>
</Window.Resources>
However, I want to beable to change where the strings are bound from, so I created a module that looks like this:
Public Module LocalizationChooser
Public ReadOnly Property GetLocalization As Uri
Get
Return New Uri("/Strings/Strings_en-US.xaml", UriKind.Relative)
End Get
End Property
End Module
Then I decided I would try changing the Source
to a Binding string. However, I've tried the following and none work:
<ResourceDictionary Source="{Binding Source={x:Static Member=StarUI:LocalizationChooser.GetLocalization}}" />
<ResourceDictionary Source="{x:Static Member=StarUI:LocalizationChooser.GetLocalization}" />
<ResourceDictionary Source="{Binding Source=StarUI:LocalizationChooser.GetLocalization}" />
<ResourceDictionary Source="{Binding Source=LocalizationChooser, Path=GetLocalization}" />
<ResourceDictionary Source="{Binding Source=StarUI:LocalizationChooser, Path=GetLocalization}" />
<ResourceDictionary Source="{Binding Source={x:Static Member=StarUI:LocalizationChooser.GetLocalization}, Path=GetLocalization}" />
<ResourceDictionary Source="{Binding Source={x:Static Member=StarUI:LocalizationChooser.GetLocalization}, Path=LocalizationChooser.GetLocalization}" />
<ResourceDictionary Source="{Binding Source={x:Static Member=StarUI:LocalizationChooser.GetLocalization}, Path=StarUI:LocalizationChooser.GetLocalization}" />
All generate the same error:
ArgumentNullException was thrown on "ResourceDictionary": Value cannot be null.
Parameter name: item
What can I do to get this working?
I should mention that the StarUI namespace is already defined as the following:
xmlns:StarUI="clr-namespace:StarUI"
EDIT:
I found that with the change I made to the module I can get the code to compile and run if I use:
<ResourceDictionary Source="{x:Static StarUI:LocalizationChooser.GetLocalization}" />
However, I still don't have design-time support. Since the module is returning a static item that doesn't need to lookup anything, is there a way to get design-time support here? If not, is there a way to specify in the XAML a static reference for design-time and then they dynamic reference for run-time?
EDIT 2:
What I finally did was to write the XAML specifying the Source
statically and then setting the constructor to 'overwrite' that. Since dictionary entries with the same name will be referenced based on the last one added, I can add a dictionary at run-time but still have a dictionary at design-time.
I used the following to localize my code simply, including design-time support and enabling dynamic changing of languages.
In my XAML I included:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary x:Name="LocalizationStrings" Source="/Strings/Strings_en-US.xaml" />
</ResourceDictionary.MergedDictionaries>
<ObjectDataProvider x:Key="objLogon" ObjectType="{x:Type StarUtilities:Logon}" />
</ResourceDictionary>
</Window.Resources>
In my code-behind:
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.Resources.MergedDictionaries.Add(GetLocalization)
End Sub
GetLocation is in a Public Module:
Public ReadOnly Property GetLocalization As ResourceDictionary
Get
Dim resourceLocalization As New ResourceDictionary
resourceLocalization.Source = New Uri("/Strings/Strings_zh-cn.xaml", UriKind.Relative)
Return resourceLocalization
End Get
End Property
A sample of my ResourceDictionary XAML is:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="ButtonLogon">Logon</sys:String>
<sys:String x:Key="ButtonCancel">Cancel</sys:String>
<sys:String x:Key="LabelUserName">User Name:</sys:String>
<sys:String x:Key="LabelPassword">Password:</sys:String>
<sys:String x:Key="LabelKey">Decryption Key:</sys:String>
</ResourceDictionary>
Then I just access the language string via:
<Label Content="{DynamicResource LabelUserName}" Name="Label1" />
Now everything works great!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要从 StaticResource 切换到 DynamicResource,因为您的资源无法立即可用。
但是您不能在 ResourceDictionary 属性上使用 Bindings,因为它不是从 DependencyObject 派生的。
You would need to switch from StaticResource to DynamicResource, since your resource isn't immediately available.
But you cannot using Bindings on the ResourceDictionary properties, as it does not derive from DependencyObject.
如果将本地化资源移动到单独的程序集中,您仍然可以在 ResourceDictionary 文件中使用静态资源。您需要将“程序集”uri 添加到标头 ns 引用中(即:
xmlns:loc="clr-namespace:MyDLL.Strings; assembly=MyDll.Localization"
)。然后,您可以像往常一样使用本地化资源,无需额外的代码:
我总是在单独的程序集中使用本地化资源。
If you move your localization resources to a separate assembly, then you can still use static resources within your ResourceDictionary files. You will need to add the "assembly" uri to your header ns reference (ie:
xmlns:loc="clr-namespace:MyDLL.Strings;assembly=MyDll.Localization"
).Then you can use your localization resources as always with no extra code:
I always use my localization resources in separate assemblies.