within your application.
In Visual Studio 2010, forms are initially represented by two files:
the generated designer file (for example, Form1.Designer.vb) and the
code-beside file (for example, Form1.vb). When a control, such as a
button, is first added to the form, a resource file (for example, Form1
.resx) is automatically created for the form. By default, this resource
file contains very little data, because most properties are hard-coded into
the designer file. This file becomes very important when localization is
turned on for the form. When this is done, via the properties grid shown
in Figure 38-4, the designer properties for the controls on the form are
persisted to the resource file. fiGure 38-4
812 .
chaPter 38 reSource FileS
The following code snippet shows the designer-generated method InitializeComponent, which
creates and sets properties on Button1. This is how the code would appear with the Localizable
property on the form set to False:
Private Sub InitializeComponent()
Me.Button1 = New Button
'
'Button1
'
Me.Button1.Location = New Point(71, 43)
Me.Button1.Size = New Size(185, 166)
Me.Button1.Text = "Button1"
Me.Button1.TabIndex = 0
Me.Button1.Name = "Button1"
Me.Button1.UseVisualStyleBackColor = True
'
'Form1
'
Me.Controls.Add(Me.Button1)
End Sub
Once the Localizable property of the form has been set to True, the form uses the new
ComponentResourceManager class to load and apply properties found in the associated resource
file. (This framework class is covered in more detail later in this chapter.)
Private Sub InitializeComponent()
Dim resources As New ComponentResourceManager(GetType(Form1))
Me.Button1 = New Button
'
'Button1
'
resources.ApplyResources(Me.Button1, "Button1")
Me.Button1.Name = "Button1"
Me.Button1.UseVisualStyleBackColor = True
'
'Form1
'
Me.Controls.Add(Me.Button1)
End Sub
Although the resource files generated by the forms designer can be manually edited, this is not
encouraged because changes may be overwritten the next time the file is regenerated by the designer.
When resource files are used properly, they can provide a number of benefits because they are a
convenient place to store strings, icons, images, and other data that might be referenced by an
application. The use of resource files, both for tracking form properties and for application data, is a
must for any application that needs to be translated for a foreign culture (we use the term “culture”
here because more than language can differ among countries and ethnic groups). Resource files
enable developers to provide alternative data for different cultures. When the application is run,
the .NET Framework uses the current culture information to determine which data to load, based
upon the resource fallback process (the fallback process is discussed in the section “Loading Culture
satellite resources .
813
Resource Files” later in this chapter). Common examples of information that might need to be
varied among cultures are prompts, titles, error messages, and button images.
control images
A number of Windows Forms controls
have images as properties. For example, the
PictureBox control has Image, ErrorImage, and
InitialImage properties. If you click the ellipsis
in the value column of the Properties window for
any of these properties, you see the dialog shown
in Figure 38-5, which enables you to select an
image for the specified property.
Before selecting an image, you have to decide
whether you want to store it in the resource
file associated with the current form (that is, a
Local resource) or in a project-level resource file.
The former option stores the image in a Base64encoded
block within the actual resource file,
whereas the latter adds the image to the project and adds an appropriate reference to the selected
resource file. Clearly the latter is normally preferable, because it means that you can change the
image without having to import it again.
satellite resources
One of the big advantages of placing data in a resource file is the resulting capability to translate the
data for foreign cultures. Instead of all the languages being included in a single resource file, each
culture’s data is stored in a resource file that has a suffix defined by that culture.
cultures
Cultures are defined by a combination of two lowercase letters, which represent the language, and two
uppercase letters, which represent the country or region of the culture. These two pairs of letters are
separated by a hyphen. For example, U.S. English and Australian English are represented as en-US
and en-AU, respectively. The corresponding resource files for these cultures would be MyResource
.en-US.resx and MyResource.en-AU.resx. You can find a full list of culture identifiers at http://
msdn2.microsoft.com/en-us/library/system.globalization.cultureinfo.aspx. If you are
curious, you can look over all the available cultures, which are returned by CultureInfo.GetCultures
(CultureTypes.AllCultures). About 220 cultures exist, and they can be classified as follows:
.
Invariant culture: No language or country identifier (for example, Form1.resx). Data is
not dependent upon culture — for example, this might be the company logo, which will not
vary and is not dependent upon culture information.
.
Neutral culture: Language identifier (for example, Form1.en.resx). Data is dependent upon
language alone — for example, a simple warning message that merely needs to be translated.
fiGure 38-5
814
.
chaPter 38 reSource FileS
.
Specific culture: Language and country identifier (for example, Form1.en-US.resx). Data is
dependent upon both language and country/region — for example, form layout, color, and
prompts should all be translated and adjusted for specific regions.
creating culture resources
If you are creating additional resource files for a form, it is important to ensure that the
Localizable property is set to True. You have three ways to create culture-specific resource files:
.
If you know the identifier of the culture for which you want to generate a resource file, you
can simply save the resx file to filename.culture_identifier.resx. For example, if you were
converting the resource file Form1.resx to Australian English, you would save it as Form1.
en-AU.resx. You will notice that when you do this, Visual Studio removes the original resx
file from the solution and adds the new culture-specific resx file. To get both files to show up
nested under the Form1 node, you actually need to exclude the new resx file, refresh the
solution view (by closing and reopening the solution), and then put both files back into
the project.
.
Visual Studio supports a much better way to create culture-specific resource files for forms.
From the Properties window for the form you can select Language. The name of this property
is slightly misleading because it adjusts not only the language, but also the country/
region of the form in designer mode. This property is initially set to (Default) and should
always be returned to this setting after you have finished generating or modifying resource
files for specific cultures. To generate the resource file for Australian English, select English
(Australia) from the Language drop-down and make the appropriate changes to the
form. Once you are comfortable with the new layout, save it and reset the Language property
to (Default).
.
The last way to generate culture-dependent resource files is to use WinRes.exe. Although
it’s not added to the Start menu, it is available under the Windows SDK folder (located at
C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin) and is a graphical utility for
generating resource files for forms. This utility can load an existing resource file, allow
properties of all controls on the form to be modified, and then save the changes to a particular
culture resource file. Before opening a form’s resource file using this utility, make sure
that the Localizable property is set to True; otherwise the file will not load properly.
loading culture resource files
At this point you might be wondering how resource files interact, and whether culture-specific
resource files have to be created and compiled at the same time as the main application. The answer
to both of these questions lies in the resource fallback process, which is the mechanism by which the
ResourceManager class loads resources.
The fallback process has three levels, based upon the current user interface culture (UI culture)
of the executing thread. This can be accessed in code via the CultureInfo.CurrentUICulture
property. Be aware that this is different from CultureInfo.CurrentCulture, which is the current
culture used in string comparisons, date formats, and so on. Unlike the current culture, which
satellite resources .
815
is based upon the regional settings of the computer (which you can adjust using Control Panel .
Regional Settings), the default UI culture is dependent upon the Windows user interface language
pack that is currently selected. Unless you have a Windows Multilingual User Interface Pack
installed, you will not be able to modify the default UI culture for your applications.
Although you can’t change the default user interface culture, you can adjust this property in code.
A word of caution here, however: without the interface pack installed, some cultures may not
display correctly.
Thread.CurrentThread.CurrentUICulture = New CultureInfo("en-US")
Using the current user interface culture, the fallback process tries to locate resources based on a
culture match. For example, if the UI culture is en-US, the process would start off by looking for
specific culture resources that match both language (English) and country (U.S.). When no resource
can be located, the process falls back to neutral culture resources that match just the language
(English). If the fallback process still can’t locate a resource, the process falls back to invariant
culture, indicating there is no match for language or country.
satellite culture resources
So far we have mentioned only how a resource can be converted into a new culture and added to
an application. Although this method gives you control over which cultures are deployed with
your application, it would be better if you didn’t have to rebuild your entire application whenever a
culture resource needed to be modified, or when you decided to add support for a new culture.
When Visual Studio 2010 compiles culture resources, it splits the resource files into a hub-andspoke
arrangement, using satellite assemblies to contain culture resources. At the hub is the main
assembly that would contain the invariant resources. Satellite assemblies are then created for each
culture for which a resource has been created. The naming of the satellite assembly is of the form
“MyApp.resources.dll” and it is located in a subdirectory named according to the culture under the
main output path. Although there is an implicit relationship between specific cultures and neutral
cultures (for example, between en-US and en), satellite assemblies for both types should reside in a
subdirectory under the main output path.
Another alternative is for the main assembly and/or satellite assemblies to be installed into the
Global Assembly Cache (GAC). In this case, each assembly must be strongly named so that it is
unique within the cache.
Clearly, the resource fallback process needs to accommodate assemblies both in the GAC and in
subdirectories. Hence, for each culture level (specific, neutral, and invariant) the GAC is checked
first, followed by the culture subdirectory. Finally, if no resource is found, an exception is raised.
Note that culture resource files do not have to contain all the resources defined in the default
resource file. The resource fallback process will load the resource from the default resource file if it
is not located in a more specific resource file, so it makes sense to save in the specified culture only
those resources that are different.
816 .
chaPter 38 reSource FileS
accessinG sPecifics
Numerous shortcuts have been built into the .NET Framework to support the most common tasks
related to accessing resources. These shortcuts include single-line image loading, cross-assembly
referencing, and the use of the ComponentResourceManager class.
bitmap and icon loading
Images and icons are two of the most common data types held in resource files. Therefore, both the
Bitmap and Icon classes in the framework support a constructor that can create an instance directly
from a resource without the need for a resource manager. For example, if you have an image,
MyImage.bmp, that you included in your project by setting the build action to Embedded Resource,
you can access the image directly using the following code:
Dim img As New Bitmap(GetType(ThisClass), "MyImage.bmp")
Here the class, ThisClass, can be any class in the root namespace of the project that contains the
embedded resource.
cross-assembly referencing
In Visual Studio 2010, you can control the accessibility level for resource files. With the Access
Modifier option in the resource editor, as shown in Figure 38-6, you can choose between keeping a
resource internal to the assembly it is defined in (Friend [VB] or Internal [C#]) or making it publicly
accessible (Public).
If you set the Access Modifier to Public, you can
then access this resource from another assembly
by prefixing the resource name with the
assembly name. For example, in the following
code the MyPerson resource is located in the fiGure 38-6
CustomResourceType assembly:
Dim p As Person = CustomResourceType.My.Resources.MyPerson
componentresourceManager
In the first example in this chapter, after localization was turned on, a ComponentResourceManager