Resources for Libraries That Target Multiple Platforms
You can use the .NET Framework Portable Class Library to ensure that resources in your class libraries can be accessed from multiple platforms.
This project is available in Visual Studio 2012 and targets the portable subset of the .NET Framework class library. Using the Portable Class Library ensures that your library can be accessed from desktop apps, Silverlight apps, Windows Phone apps, and Windows Store apps.
The Portable Class Library project makes only a very limited subset of the types in the System.Resources namespace available to your application, but it does allow you to use the ResourceManager class to retrieve resources. However, if you are creating an app by using Visual Studio, you should use the strongly typed wrapper created by Visual Studio instead of using the ResourceManager class directly. For information about using a strongly typed resource wrapper, see the "Generating a Strongly Typed Resource Class" section in the Resgen.exe (Resource File Generator) topic. You can ensure that a strongly typed wrapper is generated for each set of resource files by setting the main resource file's Access Modifier in the Visual Studio Resource Designer to Public.
In a Portable Class Library project, all access to resources is handled by the ResourceManager class. Because types in the System.Resources namespace, such as ResourceReader and ResourceSet, are not accessible from a Portable Class Library project, they cannot be used to access resources.
The Portable Class Library project includes the four ResourceManager members listed in the following table. These constructors and methods enable you to instantiate a ResourceManager object and retrieve string resources.
|
ResourceManager member |
Description |
|---|---|
|
Creates a ResourceManager instance to access the named resource file found in the specified assembly. |
|
|
Creates a ResourceManager instance that corresponds to the specified type. |
|
|
Retrieves a named resource for the current culture. |
|
|
Retrieves a named resource belonging to the specified culture. |
The exclusion of other ResourceManager members from the Portable Class Library means that serialized objects, non-string data, and images cannot be retrieved from a resource file. You may be able to work around this limitation by storing object data in string form. For example, you can store numeric values in a resource file by converting them to strings, and you can retrieve them and then convert them back to numbers by using the numeric data type's Parse or TryParse method. You can convert images or other binary data to a string representation by calling the Convert.ToBase64String method, and restore them to a byte array by calling the Convert.FromBase64String method.
Portable Class Library projects store resources in .resx files, which are then compiled into .resources files and embedded in the main assembly or in satellite assemblies at compile time. Windows Store apps, on the other hand, require resources to be stored in .resw files, which are then compiled into a single package resource index (PRI) file. However, despite the incompatible file formats, your Portable Class Library will work in a Windows Store app.
To consume your class library from a Windows Store app, add a reference to it in your Windows Store app project. Visual Studio will transparently extract the resources from your assembly into a .resw file and use it to generate a PRI file from which the Windows Runtime can extract resources. At run time, the Windows Runtime executes the code in your Portable Class Library, but it retrieves your Portable Class Library's resources from the PRI file.
If your Portable Class Library project includes localized resources, you use the hub-and-spoke model to deploy them just as you would for a library in a desktop app. To consume your main resource file and any localized resource files in your Windows Store app, you add a reference to the main assembly. At compile time, Visual Studio extracts the resources from your main resource file and any localized resource files into separate .resw files. It then compiles the .resw files into a single PRI file that the Windows Runtime accesses at run time.
The following simple, non-localized Portable Class Library example uses resources to store the names of columns and to determine the number of characters to reserve for tabular data. The example uses a file named LibResources.resx to store the string resources listed in the following table.
|
Resource name |
Resource value |
|---|---|
|
Born |
Birthdate |
|
BornLength |
12 |
|
Hired |
Hire Date |
|
HiredLength |
12 |
|
ID |
ID |
|
ID.Length |
12 |
|
Name |
Name |
|
NameLength |
25 |
|
Title |
Employee Database |
The following code defines a UILibrary class that provides a wrapper around the Resource Manager. Note that the class is in the MyCompany.Employees namespace.
Imports System.Resources <Assembly: NeutralResourcesLanguage("en-US")> Public Class UILibrary Private Const nFields As Integer = 4 Public Shared Function GetTitle() As String Dim retval As String = My.Resources.LibResources.Title If String.IsNullOrEmpty(retval) Then retval = "<No value>" Return retval End Function Public Shared Function GetFieldNames() As String() Dim fieldnames(nFields - 1) As String fieldnames(0) = My.Resources.LibResources.Name fieldnames(1) = My.Resources.LibResources.ID fieldnames(2) = My.Resources.LibResources.Born fieldnames(3) = My.Resources.LibResources.Hired Return fieldnames End Function Public Shared Function GetFieldLengths() As Integer() Dim fieldLengths(nFields - 1) As Integer fieldLengths(0) = Int32.Parse(My.Resources.LibResources.NameLength) fieldLengths(1) = Int32.Parse(My.Resources.LibResources.IDLength) fieldLengths(2) = Int32.Parse(My.Resources.LibResources.BornLength) fieldLengths(3) = Int32.Parse(My.Resources.LibResources.HiredLength) Return fieldLengths End Function End Class
The following code illustrates how the UILibrary class and its resources can be accessed from a console-mode app. It requires a reference to UILIbrary.dll to be added to the console app project.
Imports MyCompany.Employees Imports System.Collections.Generic Module Module1 Sub Main() ' Get the data from some data source. Dim employees = InitializeData() ' Display application title. Dim title As String = UILibrary.GetTitle() Dim start As Integer = (Console.WindowWidth + title.Length) \ 2 Dim titlefmt As String = String.Format("{{0,{0}{1}", start, "}") Console.WriteLine(titlefmt, title) Console.WriteLine() ' Retrieve resources. Dim fields() As String = UILibrary.GetFieldNames() Dim lengths() As Integer = UILibrary.GetFieldLengths() Dim fmtString As String = String.Empty ' Create format string for field headers and data. For ctr = 0 To fields.Length - 1 fmtString += String.Format("{{{0},-{1}{2}{3} ", ctr, lengths(ctr), IIf(ctr >= 2, ":d", ""), "}") Next ' Display the headers. Console.WriteLine(fmtString, fields) Console.WriteLine() ' Display the data. For Each e In employees Console.WriteLine(fmtString, e.Item1, e.Item2, e.Item3, e.Item4) Next Console.ReadLine() End Sub Private Function InitializeData() As List(Of Tuple(Of String, String, Date, Date)) Dim employees As New List(Of Tuple(Of String, String, Date, Date)) Dim t1 = Tuple.Create("John", "16302", #8/18/1954#, #9/8/2006#) employees.Add(t1) t1 = Tuple.Create("Alice", "19745", #5/10/1995#, #10/17/2012#) employees.Add(t1) Return employees End Function End Module
The following code illustrates how the UILibrary class and its resources can be accessed from a Windows Store app. It requires a reference to UILIbrary.dll to be added to the Windows Store app project.
Imports Microsoft.VisualBasic Imports MyCompany.Employees Imports System.Collections.Generic NotInheritable Public Class BlankPage Inherits Page Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs) Example.DisplayData(outputBlock) End Sub End Class Public Class Example Public Shared Sub DisplayData(outputBlock As Windows.UI.Xaml.Controls.TextBlock) ' Get the data from some data source. Dim employees = InitializeData() outputBlock.FontFamily = New FontFamily("Courier New") ' Display application title. Dim title As String = UILibrary.GetTitle() outputBlock.Text += title + vbCrLf + vbCrLf ' Retrieve resources. Dim fields() As String = UILibrary.GetFieldNames() Dim lengths() As Integer = UILibrary.GetFieldLengths() Dim fmtString As String = String.Empty ' Create format string for field headers and data. For ctr = 0 To fields.Length - 1 fmtString += String.Format("{{{0},-{1}{2}{3} ", ctr, lengths(ctr), If(ctr >= 2, ":d", ""), "}") Next ' Display the headers. outputBlock.Text += String.Format(fmtString, fields) + vbCrLf + vbCrLf ' Display the data. For Each e In employees outputBlock.Text += String.Format(fmtString, e.Item1, e.Item2, e.Item3, e.Item4) + vbCrLf Next End Sub Private Shared Function InitializeData() As List(Of Tuple(Of String, String, Date, Date)) Dim employees As New List(Of Tuple(Of String, String, Date, Date)) Dim t1 = Tuple.Create("John", "16302", #8/18/1954#, #9/8/2006#) employees.Add(t1) t1 = Tuple.Create("Alice", "19745", #5/10/1995#, #10/17/2012#) employees.Add(t1) Return employees End Function End Class
The following localized Portable Class Library example includes resources for the French (France) and English (United States) cultures. The English (United States) culture is the app's default culture; its resources are shown in the table in the previous section. The resources file for the French (France) culture is named LibResources.fr-FR.resx and consists of the string resources listed in the following table. The source code for the UILibrary class is the same as that shown in the previous section.
|
Resource name |
Resource value |
|---|---|
|
Born |
Date de naissance |
|
BornLength |
20 |
|
Hired |
Date embauché |
|
HiredLength |
16 |
|
ID |
ID |
|
Name |
Nom |
|
Title |
Base de données des employés |
The following code illustrates how the UILibrary class and its resources can be accessed from a console-mode app. It requires a reference to UILIbrary.dll to be added to the console app project.
Imports MyCompany.Employees Imports System.Collections.Generic Imports System.Globalization Imports System.Threading Module Module1 Sub Main() Dim culture As CultureInfo = CultureInfo.CreateSpecificCulture("fr-FR") Thread.CurrentThread.CurrentCulture = culture Thread.CurrentThread.CurrentUICulture = culture Console.WriteLine("Current culture is {0}", CultureInfo.CurrentCulture.Name) ' Get the data from some data source. Dim employees = InitializeData() ' Display application title. Dim title As String = UILibrary.GetTitle() Dim start As Integer = (Console.WindowWidth + title.Length) \ 2 Dim titlefmt As String = String.Format("{{0,{0}{1}", start, "}") Console.WriteLine(titlefmt, title) Console.WriteLine() ' Retrieve resources. Dim fields() As String = UILibrary.GetFieldNames() Dim lengths() As Integer = UILibrary.GetFieldLengths() Dim fmtString As String = String.Empty ' Create format string for field headers and data. For ctr = 0 To fields.Length - 1 fmtString += String.Format("{{{0},-{1}{2}{3} ", ctr, lengths(ctr), IIf(ctr >= 2, ":d", ""), "}") Next ' Display the headers. Console.WriteLine(fmtString, fields) Console.WriteLine() ' Display the data. For Each e In employees Console.WriteLine(fmtString, e.Item1, e.Item2, e.Item3, e.Item4) Next Console.ReadLine() End Sub Private Function InitializeData() As List(Of Tuple(Of String, String, Date, Date)) Dim employees As New List(Of Tuple(Of String, String, Date, Date)) Dim t1 = Tuple.Create("John", "16302", #8/18/1954#, #9/8/2006#) employees.Add(t1) t1 = Tuple.Create("Alice", "19745", #5/10/1995#, #10/17/2012#) employees.Add(t1) Return employees End Function End Module
The following code illustrates how the UILibrary class and its resources can be accessed from a Windows Store app. It requires a reference to UILIbrary.dll to be added to the Windows Store app project. It uses the static ApplicationPreferences.PreferredLanguage property to set the app's preferred language to French.
Imports Windows.Globalization Imports MyCompany.Employees Public NotInheritable Class BlankPage Inherits Page Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs) Example.Demo(outputBlock) End Sub End Class Public Class Example Public Shared Sub Demo(outputBlock As Windows.UI.Xaml.Controls.TextBlock) ' Set the application preferences. ApplicationPreferences.PreferredLanguage = "fr-FR" ' Get the data from some data source. Dim employees = InitializeData() outputBlock.FontFamily = New FontFamily("Courier New") ' Display application title. Dim title As String = UILibrary.GetTitle() outputBlock.Text += title + vbCrLf + vbCrLf ' Retrieve resources. Dim fields() As String = UILibrary.GetFieldNames() Dim lengths() As Integer = UILibrary.GetFieldLengths() Dim fmtString As String = String.Empty ' Create format string for field headers and data. For ctr = 0 To fields.Length - 1 fmtString += String.Format("{{{0},-{1}{2}{3} ", ctr, lengths(ctr), If(ctr >= 2, ":d", ""), "}") Next ' Display the headers. outputBlock.Text += String.Format(fmtString, fields) + vbCrLf + vbCrLf ' Display the data. For Each e In employees outputBlock.Text += String.Format(fmtString, e.Item1, e.Item2, e.Item3, e.Item4) + vbCrLf Next End Sub Private Shared Function InitializeData() As List(Of Tuple(Of String, String, Date, Date)) Dim employees As New List(Of Tuple(Of String, String, Date, Date)) Dim t1 = Tuple.Create("John", "16302", #8/18/1954#, #9/8/2006#) employees.Add(t1) t1 = Tuple.Create("Alice", "19745", #5/10/1995#, #10/17/2012#) employees.Add(t1) Return employees End Function End Class