16

I have a XBAP application with the following user control:

  <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>
    ...

Now I want to fetch the string "xxUser" from a resx file which is embed as resource in the application How do I achieve this?

coder_bro
  • 10,503
  • 13
  • 56
  • 88

6 Answers6

50

I was able to do it in a program with:

<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>

I also had to include the .Properties namespace in my xaml, like so:

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

This allowed me to not only use the string resources I had defined for my project for globalization, but I was also able to bind (two way) to my application's Settings. This let me very easily remember the window's position, size, etc. As you can see, use Settings. for settings, and Resources. for resources.

As Steven mentioned, I think the "official" way or the "best" way is to stick x:Uid on everything that you want to globalize, but I didn't and it worked with no problems. I think the x:Uid thing is mostly required if you are using automated tools or breaking the translation task up as you would in a large project. I just did all my own stuff manually in VS, so maybe it was ok.

Ben

David
  • 15,894
  • 22
  • 55
  • 66
Ben
  • 501
  • 4
  • 3
  • Thank you VERY MUCH for this helpful and informative answer. It helped me a lot -- it was last missing piece in my project :-) I was only confused with Resources -- they had to be defined via Properties of the project, not by "Add -> New Item -> Resources", right? – greenoldman Aug 12 '10 at 15:20
9

Two more additional points that I forgot to mention above in "I was able to do it...":

  1. You don't have to wrap the Properties.Resources object in your own. You can access it directly, as I have done in my example above. I think wrapping the object is a way to get the same result as I discuss in my 2nd point.
  2. By default, the resource files are built with "ResXFileCodeGenerator". This makes them internal when it generates the code file, so xaml can't access it. You have to change this to "PublicResXFileCodeGenerator", which generates public classes. You can change this by clicking the resource file in the solution explorer and editing the "Custom Tool" property.

(sorry, I couldn't edit my above post because I was a temporary member at that time.)

Benny Jobigan
  • 5,078
  • 2
  • 31
  • 41
  • 3
    ad.2. This is common omission (surprise), VS allows you to simply switch to "public" ("access modifier" combo in toolbar). No 3rd party tool is needed. – greenoldman Aug 12 '10 at 15:29
  • Thanks for this tip, I was trying to figure out why my resources were all set to internal and couldn't be used... why isn't this a dropdown field in Visual Studio? :\ – John Nov 18 '11 at 16:11
8

As Ben said, and I found an another tutorial. The access modifier of Resources.resx should be changed from Internal to Public. I failed many times and after changing the access modifier to Public, it does work.

Community
  • 1
  • 1
AechoLiu
  • 17,522
  • 9
  • 100
  • 118
7

Create a static class that makes the resources available as properties:

public static class Resources
{
   public string Resource
   {
      return Properties.Resources.ResourceManager.GetString("Resource");
   }
}

Then you can bind your TextBox to this:

<TextBlock Text="{Binding Source={x:Static local:Resources}, Path=Resource}" x:Name="upArrowUsersHeader" HorizontalAlignment="Center"
   xmlns:local="clr-namespace:MY_NAMESPACE;assembly=MY_ASSEMBLY">
Josh G
  • 14,068
  • 7
  • 62
  • 74
4

None of those answers are close to what you want. I'd start by reading about Localization in WPF. You'll find that if you are doing localization with WPF you'll want x:Uid defined on every node in your app.

http://msdn.microsoft.com/en-us/library/ms788718.aspx

Steven
  • 4,826
  • 3
  • 35
  • 44
  • 8
    I am glad it helped original poster, but usually the purpose of the forum is to add something to official documents. Just my 2 cents. – greenoldman Aug 12 '10 at 15:27
1

I don't know if this can be done directly in XAML but if you write your own wrapper class around ResourceManager and use it instead. Notice that the class inherits from TextBlock:

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

You can then use ResourceContentTextBlock in your XAML anywhere you would otherwise use a 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>
Jakob Christensen
  • 14,826
  • 2
  • 51
  • 81
  • I'm confused by this. What's going on here? Why have you defined a setter, but no getter? And do the literals "String1" in the C# and XAML have any connection? Please clarify. – Hank Dec 16 '10 at 00:03
  • You are right - I must admit this is a terrible answer with a couple of errors. I made a few chances to correct it but it is a cumbersome solution. The idea is that the ResourceName property is set to "String1" in XAML. The ResourceContentTextBlock uses this value to fetch a localized string from the resources and updates the Text property of the inherited TextBox. That's why there is no need for a get property. – Jakob Christensen Dec 16 '10 at 10:44