Utiliser des fichiers .resx par programmation
Notes
Cet article s’applique à .NET Framework. Pour plus d’informations sur .NET 5+ (y compris .NET Core), consultez Ressources dans les fichiers .resx.
Étant donné que les fichiers de ressources XML (.resx) doivent être constitués de code XML bien défini, notamment un en-tête qui doit respecter un schéma spécifique, suivi de données dans des paires nom/valeur, la création manuelle de ces fichiers est sujette aux erreurs. Alternativement, vous pouvez créer des fichiers .resx par programmation à l’aide de types et de membres de la bibliothèque de classes .NET. Vous pouvez également utiliser la bibliothèque de classes .NET pour récupérer des ressources stockées dans les fichiers .resx. Cet article explique comment utiliser les types et les membres de l’espace de noms System.Resources pour utiliser des fichiers .resx.
Cet article traite de l’utilisation de fichiers XML (.resx) contenant des ressources. Pour plus d’informations sur l’utilisation de fichiers de ressources binaires incorporés dans des assemblys, consultez ResourceManager.
Avertissement
Vous pouvez également utiliser les fichiers .resx autrement que par programmation. Quand vous ajoutez un fichier de ressources à un projet Visual Studio, ce dernier fournit une interface pour la création et la gestion d’un fichier .resx, et convertit automatiquement le fichier .resx en fichier .resources au moment de la compilation. Vous pouvez également utiliser un éditeur de texte pour manipuler directement un fichier .resx. Toutefois, pour éviter d’endommager le fichier, veillez à ne pas modifier les informations binaires stockées dans le fichier.
Créer un fichier .resx
Vous pouvez utiliser la classe System.Resources.ResXResourceWriter pour créer un fichier .resx par programmation, en procédant comme suit :
Instanciez un objet ResXResourceWriter en appelant la méthode ResXResourceWriter(String) et en fournissant le nom du fichier .resx. Le nom de fichier doit inclure l’extension .resx. Si vous instanciez l’objet ResXResourceWriter dans un bloc
using
, vous n’avez pas besoin d’appeler explicitement la méthode ResXResourceWriter.Close à l’étape 3.Appelez la méthode ResXResourceWriter.AddResource pour chaque ressource que vous voulez ajouter au fichier. Utilisez les surcharges de cette méthode pour ajouter la chaîne, l’objet et les données binaires (tableau d’octets). Si la ressource est un objet, celui-ci doit être sérialisable.
Appelez la méthode ResXResourceWriter.Close pour générer le fichier de ressources et libérer toutes les ressources. Si l’objet ResXResourceWriter a été créé dans un bloc
using
, les ressources sont écrites dans le fichier .resx et celles qui sont utilisées par l’objet ResXResourceWriter sont libérées à la fin du blocusing
.
Le fichier .resx résultant possède l’en-tête approprié et une balise data
pour chaque ressource ajoutée par la méthode ResXResourceWriter.AddResource .
Avertissement
N’utilisez pas de fichier de ressources pour stocker des mots de passe, des informations sensibles ou des données privées.
L’exemple suivant crée un fichier .resx nommé CarResources.resx qui stocke six chaînes, une icône et deux objets définis par l’application (deux objets Automobile
). La classe Automobile
, qui est définie et instanciée dans l’exemple, est marquée avec l’attribut SerializableAttribute.
using System;
using System.Drawing;
using System.Resources;
[Serializable()] public class Automobile
{
private string carMake;
private string carModel;
private int carYear;
private int carDoors;
private int carCylinders;
public Automobile(string make, string model, int year) :
this(make, model, year, 0, 0)
{ }
public Automobile(string make, string model, int year,
int doors, int cylinders)
{
this.carMake = make;
this.carModel = model;
this.carYear = year;
this.carDoors = doors;
this.carCylinders = cylinders;
}
public string Make {
get { return this.carMake; }
}
public string Model {
get {return this.carModel; }
}
public int Year {
get { return this.carYear; }
}
public int Doors {
get { return this.carDoors; }
}
public int Cylinders {
get { return this.carCylinders; }
}
}
public class Example
{
public static void Main()
{
// Instantiate an Automobile object.
Automobile car1 = new Automobile("Ford", "Model N", 1906, 0, 4);
Automobile car2 = new Automobile("Ford", "Model T", 1909, 2, 4);
// Define a resource file named CarResources.resx.
using (ResXResourceWriter resx = new ResXResourceWriter(@".\CarResources.resx"))
{
resx.AddResource("Title", "Classic American Cars");
resx.AddResource("HeaderString1", "Make");
resx.AddResource("HeaderString2", "Model");
resx.AddResource("HeaderString3", "Year");
resx.AddResource("HeaderString4", "Doors");
resx.AddResource("HeaderString5", "Cylinders");
resx.AddResource("Information", SystemIcons.Information);
resx.AddResource("EarlyAuto1", car1);
resx.AddResource("EarlyAuto2", car2);
}
}
}
Imports System.Drawing
Imports System.Resources
<Serializable()> Public Class Automobile
Private carMake As String
Private carModel As String
Private carYear As Integer
Private carDoors AS Integer
Private carCylinders As Integer
Public Sub New(make As String, model As String, year As Integer)
Me.New(make, model, year, 0, 0)
End Sub
Public Sub New(make As String, model As String, year As Integer,
doors As Integer, cylinders As Integer)
Me.carMake = make
Me.carModel = model
Me.carYear = year
Me.carDoors = doors
Me.carCylinders = cylinders
End Sub
Public ReadOnly Property Make As String
Get
Return Me.carMake
End Get
End Property
Public ReadOnly Property Model As String
Get
Return Me.carModel
End Get
End Property
Public ReadOnly Property Year As Integer
Get
Return Me.carYear
End Get
End Property
Public ReadOnly Property Doors As Integer
Get
Return Me.carDoors
End Get
End Property
Public ReadOnly Property Cylinders As Integer
Get
Return Me.carCylinders
End Get
End Property
End Class
Module Example
Public Sub Main()
' Instantiate an Automobile object.
Dim car1 As New Automobile("Ford", "Model N", 1906, 0, 4)
Dim car2 As New Automobile("Ford", "Model T", 1909, 2, 4)
' Define a resource file named CarResources.resx.
Using resx As New ResXResourceWriter(".\CarResources.resx")
resx.AddResource("Title", "Classic American Cars")
resx.AddResource("HeaderString1", "Make")
resx.AddResource("HeaderString2", "Model")
resx.AddResource("HeaderString3", "Year")
resx.AddResource("HeaderString4", "Doors")
resx.AddResource("HeaderString5", "Cylinders")
resx.AddResource("Information", SystemIcons.Information)
resx.AddResource("EarlyAuto1", car1)
resx.AddResource("EarlyAuto2", car2)
End Using
End Sub
End Module
Conseil
Vous pouvez également utiliser Visual Studio pour créer des fichiers .resx. Au moment de la compilation, Visual Studio utilise l’outil Resource File Generator (Resgen.exe) pour convertir le fichier .resx en fichier de ressources binaires (.resources), et l’incorpore dans un assembly d’application ou un assembly satellite.
Vous ne pouvez pas incorporer un fichier .resx dans un exécutable du Common Language Runtime ou le compiler dans un assembly satellite. Vous devez convertir votre fichier .resx en fichier de ressources binaires (.resources) à l’aide de l’outil Resource File Generator (Resgen.exe). Le fichier .resources résultant peut ensuite être incorporé dans un assembly d’application ou un assembly satellite. Pour plus d’informations, consultez Créer des fichiers de ressources.
Énumérer les ressources
Dans certains cas, vous voulez récupérer toutes les ressources d’un fichier .resx, et pas seulement une ressource spécifique. Pour ce faire, vous pouvez utiliser la classe System.Resources.ResXResourceReader , qui fournit un énumérateur pour toutes les ressources du fichier .resx. La classe System.Resources.ResXResourceReader implémente IDictionaryEnumerator, qui retourne un objet DictionaryEntry représentant une ressource particulière pour chaque itération de la boucle. Sa propriété DictionaryEntry.Key retourne la clé de la ressource et sa propriété DictionaryEntry.Value retourne la valeur de la ressource.
L’exemple suivant crée un objet ResXResourceReader pour le fichier CarResources.resx créé dans l’exemple précédent et itère au sein du fichier de ressources. Il ajoute les deux objets Automobile
définis dans le fichier de ressources à un objet System.Collections.Generic.List<T> , et ajoute cinq des six chaînes à un objet SortedList . Les valeurs de l’objet SortedList sont converties en tableau de paramètres, utilisé pour afficher des en-têtes de colonne dans la console. Les valeurs de propriété Automobile
sont également affichées dans la console.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Resources;
public class Example
{
public static void Main()
{
string resxFile = @".\CarResources.resx";
List<Automobile> autos = new List<Automobile>();
SortedList headers = new SortedList();
using (ResXResourceReader resxReader = new ResXResourceReader(resxFile))
{
foreach (DictionaryEntry entry in resxReader) {
if (((string) entry.Key).StartsWith("EarlyAuto"))
autos.Add((Automobile) entry.Value);
else if (((string) entry.Key).StartsWith("Header"))
headers.Add((string) entry.Key, (string) entry.Value);
}
}
string[] headerColumns = new string[headers.Count];
headers.GetValueList().CopyTo(headerColumns, 0);
Console.WriteLine("{0,-8} {1,-10} {2,-4} {3,-5} {4,-9}\n",
headerColumns);
foreach (var auto in autos)
Console.WriteLine("{0,-8} {1,-10} {2,4} {3,5} {4,9}",
auto.Make, auto.Model, auto.Year,
auto.Doors, auto.Cylinders);
}
}
// The example displays the following output:
// Make Model Year Doors Cylinders
//
// Ford Model N 1906 0 4
// Ford Model T 1909 2 4
Imports System.Collections
Imports System.Collections.Generic
Imports System.Resources
Module Example
Public Sub Main()
Dim resxFile As String = ".\CarResources.resx"
Dim autos As New List(Of Automobile)
Dim headers As New SortedList()
Using resxReader As New ResXResourceReader(resxFile)
For Each entry As DictionaryEntry In resxReader
If CType(entry.Key, String).StartsWith("EarlyAuto") Then
autos.Add(CType(entry.Value, Automobile))
Else If CType(entry.Key, String).StartsWith("Header") Then
headers.Add(CType(entry.Key, String), CType(entry.Value, String))
End If
Next
End Using
Dim headerColumns(headers.Count - 1) As String
headers.GetValueList().CopyTo(headerColumns, 0)
Console.WriteLine("{0,-8} {1,-10} {2,-4} {3,-5} {4,-9}",
headerColumns)
Console.WriteLine()
For Each auto In autos
Console.WriteLine("{0,-8} {1,-10} {2,4} {3,5} {4,9}",
auto.Make, auto.Model, auto.Year,
auto.Doors, auto.Cylinders)
Next
End Sub
End Module
' The example displays the following output:
' Make Model Year Doors Cylinders
'
' Ford Model N 1906 0 4
' Ford Model T 1909 2 4
Récupérer une ressource spécifique
Outre l’énumération des éléments d’un fichier .resx, vous pouvez récupérer une ressource spécifique par son nom à l’aide de la classe System.Resources.ResXResourceSet . La méthode ResourceSet.GetString(String) extrait la valeur d’une ressource de chaîne nommée. La méthode ResourceSet.GetObject(String) extrait la valeur d’un objet nommé ou des données binaires. La méthode retourne un objet qui doit être casté (en C#) ou converti (en Visual Basic) en objet de type approprié.
L’exemple suivant récupère la chaîne et l’icône de la légende d’un formulaire par leur nom de ressources. Elle récupère également les objets Automobile
définis par l’application utilisés dans l’exemple précédent et les affiche dans un contrôle DataGridView.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Resources;
using System.Windows.Forms;
public class CarDisplayApp : Form
{
private const string resxFile = @".\CarResources.resx";
Automobile[] cars;
public static void Main()
{
CarDisplayApp app = new CarDisplayApp();
Application.Run(app);
}
public CarDisplayApp()
{
// Instantiate controls.
PictureBox pictureBox = new PictureBox();
pictureBox.Location = new Point(10, 10);
this.Controls.Add(pictureBox);
DataGridView grid = new DataGridView();
grid.Location = new Point(10, 60);
this.Controls.Add(grid);
// Get resources from .resx file.
using (ResXResourceSet resxSet = new ResXResourceSet(resxFile))
{
// Retrieve the string resource for the title.
this.Text = resxSet.GetString("Title");
// Retrieve the image.
Icon image = (Icon) resxSet.GetObject("Information", true);
if (image != null)
pictureBox.Image = image.ToBitmap();
// Retrieve Automobile objects.
List<Automobile> carList = new List<Automobile>();
string resName = "EarlyAuto";
Automobile auto;
int ctr = 1;
do {
auto = (Automobile) resxSet.GetObject(resName + ctr.ToString());
ctr++;
if (auto != null)
carList.Add(auto);
} while (auto != null);
cars = carList.ToArray();
grid.DataSource = cars;
}
}
}
Imports System.Collections.Generic
Imports System.Drawing
Imports System.Resources
Imports System.Windows.Forms
Public Class CarDisplayApp : Inherits Form
Private Const resxFile As String = ".\CarResources.resx"
Dim cars() As Automobile
Public Shared Sub Main()
Dim app As New CarDisplayApp()
Application.Run(app)
End Sub
Public Sub New()
' Instantiate controls.
Dim pictureBox As New PictureBox()
pictureBox.Location = New Point(10, 10)
Me.Controls.Add(pictureBox)
Dim grid As New DataGridView()
grid.Location = New Point(10, 60)
Me.Controls.Add(grid)
' Get resources from .resx file.
Using resxSet As New ResXResourceSet(resxFile)
' Retrieve the string resource for the title.
Me.Text = resxSet.GetString("Title")
' Retrieve the image.
Dim image As Icon = CType(resxSet.GetObject("Information", True), Icon)
If image IsNot Nothing Then
pictureBox.Image = image.ToBitmap()
End If
' Retrieve Automobile objects.
Dim carList As New List(Of Automobile)
Dim resName As String = "EarlyAuto"
Dim auto As Automobile
Dim ctr As Integer = 1
Do
auto = CType(resxSet.GetObject(resName + ctr.ToString()), Automobile)
ctr += 1
If auto IsNot Nothing Then carList.Add(auto)
Loop While auto IsNot Nothing
cars = carList.ToArray()
grid.DataSource = cars
End Using
End Sub
End Class
Convertir les fichiers .resx en fichiers binaires .resources
La conversion de fichiers .resx en fichiers de ressources binaires incorporés (.resources) présente des avantages importants. Bien que les fichiers .resx soient faciles à lire et à gérer pendant le développement d’applications, ils sont rarement inclus avec les applications finies. S’ils sont distribués avec une application, ils existent en tant que fichiers séparés de l’exécutable de l’application et des bibliothèques qui l’accompagnent. En revanche, les fichiers .resources sont incorporés dans l’exécutable d’application ou dans les assemblys qui l’accompagnent. Par ailleurs, pour les applications localisées, l’utilisation de fichiers .resx au moment de l’exécution donne au développeur la responsabilité de la gestion des ressources de secours. En revanche, si un ensemble d’assemblys satellites contenant des fichiers .resources incorporés a été créé, le Common Language Runtime gère le processus de secours pour les ressources.
Pour convertir un fichier .resx en fichier .resources, vous utilisez l’outil Resource File Generator (resgen.exe), qui présente la syntaxe de base suivante :
resgen.exe .resxFilename
Le résultat est un fichier de ressources binaires ayant le même nom de fichier racine que celui du fichier .resx et une extension de fichier .resources. Ce fichier peut ensuite être compilé en exécutable ou bibliothèque au moment de la compilation. Si vous utilisez le compilateur Visual Basic, utilisez la syntaxe suivante pour incorporer un fichier .resources dans l’exécutable d’une application :
vbc filename .vb -resource: .resourcesFilename
Si vous utilisez C#, la syntaxe est la suivante :
csc filename .cs -resource: .resourcesFilename
Le fichier .resources peut également être incorporé dans un assembly satellite à l’aide de l’utilitaire Assembly Linker (al.exe), qui présente la syntaxe de base suivante :
al resourcesFilename -out: assemblyFilename