Resource Files


Resource files contain text, images, and other data for the application to load at runtime. The intent of resource files is to let you easily replace one set of resources with another. One of the most common reasons for using resource files is to provide different resources for different languages. To create installation packages for different languages, you simply ship the executable and a resource file that uses the right language. Alternatively, you can ship resource files for all of the languages you support and then let the application pick the appropriate file at runtime based on the user’s computer settings.

Resource files are not intended to store application configuration information and settings. They are intended to hold values that you might want to change, but only infrequently. Configurations and settings, on the other hand, may change relatively often. You should store that kind of data in configuration files or the System Registry.

The distinction is small and frankly somewhat artificial. Both configuration files and resource files store data that you can swap without recompiling the application. Rebuilding resource files can be a little more complex, however, so perhaps the distinction that configuration and setting data changes more frequently makes some sense.

Resource files can also be embedded within a compiled application. In that case, you cannot swap the resource file without recompiling the application. Although this makes embedded resource files less useful for storing frequently changing information, they still give you a convenient place to group resource data within the application. This is particularly useful if several parts of the application must use the same pieces of data. For example, if every form should display the same background image, it makes sense to store the image in a common resource file that they can all use.

The following sections describe the four most common types of resources: application, embedded, satellite, and localization.

Application Resources

To create application resources in Visual Basic, open Solution Explorer, double-click the My Project entry, and select the Resources tab. Use the drop-down on the left to select one of the resource categories: Strings, Images, Icons, Audio, Files, or Other. Figure 27-7 shows the application’s resources tab displaying the application’s images.

image from book
Figure 27-7: The Resources tab contains image and other resources used by the application.

If you double-click on an item, Visual Studio opens an appropriate editor. Figure 27-8 shows the Dog picture in the integrated bitmap editor.

image from book
Figure 27-8: If you double-click on a resource, Visual Studio opens it in an appropriate editor.

Figure 27-9 shows the string resource editor. Click an entry and type to create or modify a value. Click to the left of the Name column to select a row and then click the Remove button or press the Delete key to remove a string.

image from book
Figure 27-9: The string resource view lets you edit string resources in a grid.

Click the Add Resource drop-down list and select the New String, New Image, New Icon, or New Text File command to add new items to the resource file. The New Image item opens a cascading submenu that lets you create new PNG, bitmap, GIF, JPEG, and TIFF images.

Using Application Resources

When you create application resources, Visual Studio automatically generates code that adds strongly typed resource properties to the My.Resources namespace. If you open Solution Explorer and click the Show All Files button, you can see the file Resources.Designer.vb below the Resources.resx item. This file is highlighted in Figure 27-10.

image from book
Figure 27-10: The file Resources.Designer.vb contains strongly typed properties that fetch resource values.

For example, the following code shows the property that Resources.Designer.vb contains to retrieve the Octahedron image resource:

  Friend ReadOnly Property Octahedron() As System.Drawing.Bitmap     Get         Return CType(ResourceManager.GetObject("Octahedron", _             resourceCulture),System.Drawing.Bitmap)     End Get End Property 

The following code shows how a program can use these My.Resources properties. It sets the lblGreeting control’s Text property to the string returned by the My.Resources.Greeting property. Then it sets the form’s BackgroundImage property to the image resource named Dog.

  Private Sub Form1_Load(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles MyBase.Load     lblGreeting.Text = My.Resources.Greeting     Me.BackgroundImage = My.Resources.Dog End Sub 

Because these property procedures are strongly typed, IntelliSense can offer support for them. If you type My.Resources, IntelliSense lists the values defined in the application’s resource file.

The strongly typed resources properties use a ResourceManager object to fetch the application’s resources. The My.Resources namespace exposes that object through its ResourceManager property, so you can use that object directly to retrieve the application’s resources. The following code does the same things as the previous version, except it uses the ResourceManager directly. Note that the ResourceManager property’s GetObject method returns a generic Object, so the code uses CType to convert the result into an Image before assigning it to the form’s BackgroundImage property.

  Private Sub Form1_Load(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles MyBase.Load     lblGreeting.Text = My.Resources.ResourceManager.GetString("Greeting")     Me.BackgroundImage = CType( _         My.Resources.ResourceManager.GetObject("Dog"), _         Image) End Sub 

Generally, you should use the automatically generated resource properties in the My.Resources namespace because they are easier to use and they are strongly typed. The ResourceManager class is much more useful when you use other embedded resource files.

Embedded Resources

In addition to storing resources in the application’s resource file Resources.resx, you can add other resources files to the application. Open the Project menu and select the Add New item command. Pick the Resources File template, give the file a meaningful name, and click OK.

After you add a resource file to the project, you can double-click it in Solution Explorer to open it in the resource editor. Then you can add resources to the file exactly as you do for the application’s resources file.

At runtime, you can use a ResourceManager object to fetch the resources from the embedded file. The following code loads the Dog image from the file Images.resx and the string Greeting from the file StringResources.resx.

It starts by declaring a ResourceManager variable. It then initializes the variable, passing its constructor the resource file’s path and the assembly containing the file. The file’s path consists of the application’s root namespace EmbeddedResources followed by the file’s name Images.

The program then uses the ResourceManager object’s GetObject method to fetch the Dog image, converts the generic Object returned into an Image, and assigns the result to the form’s BackgroundImage property.

Next, the code reinitializes the ResourceManager object so it represents the StringResources resource file. It calls the manager’s GetString method to get the value of the Greeting resource and saves the result in the lblGreeting control’s Text property.

  Private Sub Form1_Load(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles MyBase.Load     Dim resource_manager As ResourceManager     ' Get the Dog image from Images.resx.     resource_manager = New ResourceManager( _         "EmbeddedResources.Images", _         Me.GetType.Assembly)     Me.BackgroundImage = CType( _         resource_manager.GetObject("Dog"), _         Image)     ' Get the Greeting from StringResources.resx.     resource_manager = New ResourceManager( _         "EmbeddedResources.StringResources", _         Me.GetType.Assembly)     lblGreeting.Text = resource_manager.GetString("Greeting") End Sub 

Strongly Typed Embedded Resources

Just as it can generate code to provide properties that fetch application resources, Visual Studio can generate similar code for other embedded resource files. Select the file in Solution Explorer and open the Properties window. Set the file’s Custom Tool property to VbMyResourcesResXFileCodeGenerator. Then set its Custom Tool Namespace property to the namespace that you want to contain the resource properties. For example, you might set this value for a string resource file to My.StringResources. The following code shows how the program could use the automatically generated Greeting property:

  lblGreeting.Text = My.StringResources.Greeting 

Setting the Custom Tool and Custom Tool Namespace properties requires some lengthy typing, but once you’ve set these values, using the strongly typed properties is much easier than fetching resources by using a ResourceManager.

Satellite Resources

Embedded resource files enable you to organize data in central locations. For example, you can keep all the images used by the application in a single resource file, and all of the program’s forms can fetch the images from that file.

Rather than embedding a resource file in the application, you can load it at runtime. Then if you must make changes to the resources, you can replace the resource file and the program will load the new resources the next time it runs.

To make switching resources easy, you can place them in a resource-only assembly. This satellite assembly contains data for the application but doesn’t contain any program logic.

To make a resource-only satellite assembly, start a new Visual Basic project, selecting the Class Library template. Delete the project’s initial class. Then, add resources to the project as you would add them to any other project. You can add resources to the project’s resources or to embedded resource files. When you are finished adding resources, compile the project to build a .dll file.

You can then build an executable Windows application that loads resources from the assembly as shown in the following code. The program declares an Assembly object and uses the shared Assembly.LoadForm method to load information about the resource-only assembly SatelliteResources.dll. In this example, the file was copied into the executable program’s startup directory so the program does not need to pass a complete path to the LoadFrom method.

Next, the program uses the Assembly object to create a ResourceManager. For the resource file’s name, it passes the ResourceManager object’s constructor the assembly’s root namespace SatelliteResources, followed by the name of the resource file within the satellite project. In this case, the first resource is stored in the project’s resources, so the file is MyResources.resx. Now the program uses the ResourceManager object’s GetString method to fetch the Greeting resource.

The program then creates a new ResourceManager using the same Assembly object, this time using the resource file named ImageResources.resx. It uses the GetObject method to fetch the image named Dog, converts the result into an Image, and saves the result in the form’s BackgroundImage property.

  Private Sub Form1_Load(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles MyBase.Load     ' Get the resource Assembly.     Dim satellite_assembly As Assembly     satellite_assembly = Assembly.LoadFrom("SatelliteResources.dll")     ' Create a ResourceManager for the satellite's     ' main resource file.     Dim resource_manager As ResourceManager     resource_manager = New ResourceManager( _         "SatelliteResources.Resources", _         satellite_assembly)     ' Get the string resource from the satellite's     ' main resource file.     lblGreeting.Text = resource_manager.GetString("Greeting")     ' Create a ResourceManager for the satellite's     ' Images resource file.     resource_manager = New ResourceManager( _         "SatelliteResources.Images", _         satellite_assembly)     ' Get the form's background image from      ' Images resource file.     Me.BackgroundImage = CType( _         resource_manager.GetObject("Dog"), Image) End Sub 

Later, if you must change the value of the Greeting string or the Dog image, you can update the satellite project, build a new DLL file, and copy the DLL file into the executable program’s startup directory. The next time you run the program, it will load the new resources.

Localization Resources

One of the most important reasons for inventing resource files was to allow localization: supporting different text, images, and other items for different languages and cultures. In Visual Studio .NET, localization is easy.

First, create a form using whatever language you typically use from day to day. For me, that’s English as spoken in the United States. Open the form in the form designer and give it whatever controls you need. Set the form’s and controls’ properties as usual.

Next, set the form’s Localizable property to True. Then set the form’s Language property to the first language you want to support other than the default language that you have been working with so far. Modify the controls’ properties for the new language.

As you modify a form, Visual Studio saves the changes you make into a new resource file attached to the form. Figure 27-11 shows the Solution Explorer for an application with a form that has English and German resources. Below the Form1.vb entry, you can see two resource files. The default file containing English resources is named Form1.resx. The resource file containing the German settings is named Form1.de.resx.

image from book
Figure 27-11: Visual Studio saves resources for different languages in separate resource files.

At runtime, the application automatically checks the user’s computer and selects the correct resource file based on the system’s regional settings.

Normally, you should let the application pick the appropriate resource file automatically, but you can explicitly select a resource file for testing purposes. To do that, open the Solution Explorer and click the Show All Files button. Find the form’s design file (for example, Form1.Designer.vb) and open it.

Give the form an empty constructor that sets the current thread’s CurrentCulture and CurrentUICulture properties to the culture that you want to use. See the online help for the CultureInfo class to get a list of possible cultures such as en-US (US English) or de-DE (German). The result should look something like the following code:

  Imports System.Threading Imports System.Globalization Public Class Form1     Public Sub New()         MyBase.New()         ' Set the culture and UI culture to German.         Thread.CurrentThread.CurrentCulture = New CultureInfo("de-DE")         Thread.CurrentThread.CurrentUICulture = New CultureInfo("de-DE")         'This call is required by the Windows Form Designer.         InitializeComponent()     End Sub End Class 

The rest is automatic. When the form’s InitializeComponent method executes, it loads the resources it needs for the culture you selected.

ComponentResourceManager

The ResourceManager class provides tools for loading resources from a resource file one at a time. The ComponentResourceManager class also provides GetString and GetObject methods that work much as the ResourceManager object’s methods do.

ComponentResourceManager also provides the ApplyResources method, which makes applying resources to an object easier. ApplyResources searches a resource file for items with a particular object name. It then applies any resources it finds to an object’s properties.

For example, you could use ApplyResources to search for resources with the object name ExitButton and apply them to the btnExit control. If the resource file contained an item named ExitButton.Text, ApplyResources would apply it to the btnExit control’s Text property. If the method found other resources (such as ExitButton.Location and ExitButton.Size), it would apply those properties to the control, too.

When you localize a form, Visual Studio automatically creates entries in the appropriate resource files for the form’s controls. If you set the form’s Language to German and set the btnYes button’s Text property to Ja, then Visual Studio adds a string entry named btnYes.Text with value Ja to the form’s German resource file.

Visual Studio uses the special name $this to represent the form’s properties. For example, if you set the form’s Text property, the IDE adds a string resource named $this.Text to the appropriate resource file.

Figure 27-12 shows the German string resources for Form1 stored in the file Form1.de.resx. The resources define values for the form itself ($this), and the radEnglish, radGerman, and lblPrompt controls.

image from book
Figure 27-12: Locale-specific resource files include values for specific controls.

The following code uses ComponentResourceManager objects to load different localized resources. When the user clicks the radEnglish radio button, the program creates a new CultureInfo object representing United States English. It creates a ComponentResourceManager for the form’s type, and uses its Apply?Resources method to apply any English form resources to the form. It then loops through the form’s controls, using ApplyResources to apply any English resources for the form’s controls. When it is finished, the form and all of its controls are using the English resources. When the user clicks the radGerman radio button, the program similarly applies the German resources to the form and its controls.

  ' Select English. Private Sub radEnglish_CheckedChanged(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles radEnglish.CheckedChanged     Dim culture_info As New CultureInfo("en-US")     Dim component_resource_manager As New ComponentResourceManager(Me.GetType)     component_resource_manager.ApplyResources(Me, "$this", culture_info)     For Each ctl As Control In Me.Controls         component_resource_manager.ApplyResources(ctl, ctl.Name, culture_info)     Next ctl End Sub ' Select German. Private Sub radGerman_CheckedChanged(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles radGerman.CheckedChanged     Dim culture_info As New CultureInfo("de-DE")     Dim component_resource_manager As New ComponentResourceManager(Me.GetType)     component_resource_manager.ApplyResources(Me, "$this", culture_info)     For Each ctl As Control In Me.Controls         component_resource_manager.ApplyResources(ctl, ctl.Name, culture_info)     Next ctl End Sub 

The following code shows a slightly different method for accomplishing the same tasks. Instead of passing a CultureInfo object into the ApplyResources method, the program sets the current thread’s CurrentCulture and CurrentUICulture properties. It then calls ApplyResources and lets it use those properties to figure out which resource file to use.

  ' Select English. Private Sub radEnglish_CheckedChanged(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles radEnglish.CheckedChanged     ' Set the current culture and UI culture.     Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")     Thread.CurrentThread.CurrentUICulture = New CultureInfo("en-US")     ' Load resources.     Dim component_resource_manager As New ComponentResourceManager(Me.GetType)     component_resource_manager.ApplyResources(Me, "$this")     For Each ctl As Control In Me.Controls         component_resource_manager.ApplyResources(ctl, ctl.Name)     Next ctl End Sub ' Select German. Private Sub radGerman_CheckedChanged(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles radGerman.CheckedChanged     ' Set the current culture and UI culture.     Thread.CurrentThread.CurrentCulture = New CultureInfo("de-DE")     Thread.CurrentThread.CurrentUICulture = New CultureInfo("de-DE")     ' Load resources.     Dim component_resource_manager As New ComponentResourceManager(Me.GetType)     component_resource_manager.ApplyResources(Me, "$this")     For Each ctl As Control In Me.Controls         component_resource_manager.ApplyResources(ctl, ctl.Name)     Next ctl End Sub 

The program can later use the CurrentCulture and CurrentUICulture properties if it needs to remember which culture it is currently using.




Visual Basic 2005 with  .NET 3.0 Programmer's Reference
Visual Basic 2005 with .NET 3.0 Programmer's Reference
ISBN: 470137053
EAN: N/A
Year: 2007
Pages: 417

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net