ResourceDictionary Source Binding to Module (for Localization)

柔情痞子 提交于 2019-12-10 10:19:26

问题


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!


回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/5623008/resourcedictionary-source-binding-to-module-for-localization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!