如何从资源中获取字符串以在WPF XAML资源部分中分配

16
我有一个 XBAP 应用程序,并有以下用户控件:
  <UserControl x:Class="XXX.UsersGrid"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="Auto" Width="Auto">

        <UserControl.Resources>
            <DataTemplate x:Key="UpArrowUsers">
                <DockPanel>
                    <TextBlock Text="xxUser" x:Name="upArrowUsersHeader" HorizontalAlignment="Center"></TextBlock>
                    <Path x:Name="arrow" StrokeThickness = "1" Fill= "gray" Data= "M 5,10 L 15,10 L 10,5 L 5,10"/>
                </DockPanel>
            </DataTemplate>
    </UserControl>
    ...

我现在想从一个作为应用程序资源嵌入的resx文件中获取字符串"xxUser",我该如何实现?

6个回答

50

我在一个程序中成功完成了这个操作:

<TextBlock VerticalAlignment="Center" Margin="3"
           Text="{x:Static prop:Resources.OpenButton}"
           Visibility="{Binding Source={x:Static prop:Settings.Default}, Path=ShowButtonText, 
           Converter={StaticResource BoolToVis}}"></TextBlock>

我还必须在我的xaml中包含.Properties命名空间,就像这样:

xmlns:prop="clr-namespace:MyProjectNamespace.Properties"

这使我不仅可以使用我为项目定义的字符串资源进行全球化,还能够双向绑定我的应用程序设置。这样我可以非常容易地记住窗口的位置、大小等等。正如你所看到的,使用“Settings”来设置设置,“Resources”来设置资源。

正如Steven提到的那样,我认为“官方”的方式或者“最佳”的方式是将x:Uid附加到您想要全球化的所有内容上,但我没有这样做,而且也没有出现任何问题。我认为只有在使用自动化工具或者像大型项目中一样分解翻译任务时,才需要使用x:Uid。我只是在VS中手动完成了所有操作,所以也许没关系。

Ben


非常感谢你这个有帮助且详细的解答,它对我帮助很大——这是我项目中缺失的最后一块拼图 :-) 我之前只是对Resources有点困惑——它们需要通过项目属性来定义,而不是通过“添加 -> 新建项 -> 资源”,对吗? - greenoldman

10

我之前在"I was able to do it..."中忘记提到的另外两个要点:

  1. 你不需要将Properties.Resources对象包装在自己的对象中。你可以像我在上面的例子中所做的那样直接访问它。我认为包装对象是一种获得我在第二点中讨论的相同结果的方法。
  2. 默认情况下,资源文件使用"ResXFileCodeGenerator"构建。这使它们在生成代码文件时变成了内部文件,因此xaml无法访问它们。你必须将其更改为"PublicResXFileCodeGenerator",这将生成公共类。你可以通过单击解决方案资源管理器中的资源文件并编辑"Custom Tool"属性来更改此设置。

(抱歉,我当时是临时成员,无法编辑我的上述帖子。)


3
这是一个常见的遗漏(让人惊讶),VS让你可以简单地切换到“public”(工具栏中的“access modifier”组合)而不需要第三方工具。 - greenoldman
谢谢这个提示,我一直在试图弄清楚为什么我的资源都设置为内部资源,无法使用...为什么Visual Studio中没有下拉菜单呢?:\ - John

8
正如Ben所说,并且我找到了另一个教程Resources.resx访问修饰符应该从Internal更改为Public。在多次失败之后,将访问修饰符更改为Public,它确实有效。

7
创建一个静态类,将资源作为属性提供:
public static class Resources
{
   public string Resource
   {
      return Properties.Resources.ResourceManager.GetString("Resource");
   }
}

然后,您可以将您的文本框绑定到此处:
<TextBlock Text="{Binding Source={x:Static local:Resources}, Path=Resource}" x:Name="upArrowUsersHeader" HorizontalAlignment="Center"
   xmlns:local="clr-namespace:MY_NAMESPACE;assembly=MY_ASSEMBLY">

4

8
我很高兴它对原贴作者有所帮助,但通常论坛的目的是为官方文件添加内容。这只是我的个人意见。 - greenoldman

1

我不确定在XAML中是否可以直接完成这个操作,但如果您编写自己的包装类来封装ResourceManager并使用它,那么就可以实现。请注意,该类继承自TextBlock:

public class ResourceContentTextBlock : TextBlock
{
    public string ResourceName 
    {
        set
        {
            this.Text = Properties.Resources.ResourceManager.GetString(value);
        }
    }
}

然后,您可以在XAML中的任何位置使用ResourceContentTextBlock,就像您使用TextBlock一样:

<Window x:Class="WpfApplication3.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:client="clr-namespace:WpfApplication3" 
    >
        <client:ResourceContentTextBlock ResourceName="String1" />
</Window>

我对此感到困惑。这里发生了什么?你为什么定义了一个setter,但没有getter?C#和XAML中的文字“String1”是否有任何联系?请澄清一下。 - Hank
你是对的 - 我必须承认这个答案很糟糕,有几个错误。我做了一些更改来纠正它,但这是一个笨重的解决方案。思路是在XAML中将ResourceName属性设置为"String1"。ResourceContentTextBlock使用此值从资源中获取本地化字符串,并更新继承TextBox的Text属性。因此,不需要get属性。 - Jakob Christensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接