Reputation: 4479
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!
Upvotes: 3
Views: 7882
Reputation: 1207
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:
<Label Content="{x:Static loc:LocalizationStrings.TitleXXX}" />
I always use my localization resources in separate assemblies.
Upvotes: 0
Reputation: 41393
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.
Upvotes: 4