Partager via


Utiliser des fichiers .resx par programmation

Remarque

Cet article s’applique à .NET Framework. Pour plus d’informations qui s’appliquent à .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 xml bien définis, y compris un en-tête qui doit suivre un schéma spécifique suivi de données dans des paires nom/valeur, vous pouvez constater que la création manuelle de ces fichiers est sujette à des erreurs. En guise d’alternative, vous pouvez créer des fichiers .resx par programmation à l’aide de types et de membres dans 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 des fichiers .resx. Cet article explique comment utiliser les types et les membres de l’espace de noms System.Resources pour travailler avec des fichiers .resx.

Cet article traite de l’utilisation de fichiers XML (.resx) qui contiennent des ressources. Pour plus d’informations sur l’utilisation de fichiers de ressources binaires incorporés dans des assemblys, consultez ResourceManager.

Avertissement

Il existe également des façons d’utiliser des fichiers .resx autres que par programme. Lorsque vous ajoutez un fichier de ressources à un projet Visual Studio , Visual Studio fournit une interface permettant de créer et de gérer 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 un fichier .resx directement. 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 System.Resources.ResXResourceWriter classe pour créer un fichier .resx par programme, en procédant comme suit :

  1. Instanciez un ResXResourceWriter objet en appelant la ResXResourceWriter(String) méthode 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 using bloc, vous n’avez pas à appeler explicitement la méthode à l’étape ResXResourceWriter.Close 3.

  2. Appelez la ResXResourceWriter.AddResource méthode pour chaque ressource que vous souhaitez ajouter au fichier. Utilisez les surcharges de cette méthode pour ajouter des données de chaîne, d’objet et de binaire (tableau d’octets). Si la ressource est un objet, elle doit être sérialisable.

  3. Appelez la ResXResourceWriter.Close méthode pour générer le fichier de ressources et libérer toutes les ressources. Si l’objet ResXResourceWriter a été créé dans un using bloc, les ressources sont écrites dans le fichier .resx et les ressources utilisées par l’objet ResXResourceWriter sont libérées à la fin du using bloc.

Le fichier .resx résultant a l’en-tête approprié et une data balise pour chaque ressource ajoutée par la ResXResourceWriter.AddResource méthode.

Avertissement

N’utilisez pas de fichiers de ressources pour stocker les mots de passe, les informations sensibles à la sécurité ou les 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 Automobile objets). La Automobile classe, 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 / Astuce

Vous pouvez également utiliser Visual Studio pour créer des fichiers .resx. Au moment de la compilation, Visual Studio utilise le générateur de fichiers de ressources (Resgen.exe) pour convertir le fichier .resx en fichier de ressource binaire (.resources) et l’incorpore également dans un assembly d’application ou un assembly satellite.

Vous ne pouvez pas incorporer un fichier .resx dans un exécutable runtime ou le compiler dans un assembly satellite. Vous devez convertir votre fichier .resx en fichier de ressource binaire (.resources) à l’aide du générateur de fichiers de ressources (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 pouvez récupérer toutes les ressources, au lieu d’une ressource spécifique, à partir d’un fichier .resx. Pour ce faire, vous pouvez utiliser la System.Resources.ResXResourceReader classe, qui fournit un énumérateur pour toutes les ressources du fichier .resx. La System.Resources.ResXResourceReader classe implémente IDictionaryEnumerator, qui retourne un DictionaryEntry objet qui représente une ressource particulière pour chaque itération de la boucle. Sa DictionaryEntry.Key propriété retourne la clé de la ressource et sa DictionaryEntry.Value propriété 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 effectue une itération dans le fichier de ressources. Il ajoute les deux Automobile objets définis dans le fichier de ressources à un System.Collections.Generic.List<T> objet et ajoute cinq des six chaînes à un SortedList objet. Les valeurs de l’objet SortedList sont converties en tableau de paramètres, qui est utilisé pour afficher les en-têtes de colonne dans la console. Les valeurs de Automobile propriété 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

En plus d’énumérer les éléments d’un fichier .resx, vous pouvez récupérer une ressource spécifique par nom à l’aide de la System.Resources.ResXResourceSet classe. La ResourceSet.GetString(String) méthode récupère la valeur d’une ressource de chaîne nommée. La ResourceSet.GetObject(String) méthode récupère la valeur d’un objet nommé ou de données binaires. La méthode retourne un objet qui doit ensuite être casté (en C#) ou converti (en Visual Basic) en objet du 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. Il récupère également les objets définis par Automobile l’application utilisés dans l’exemple précédent et les affiche dans un DataGridView contrôle.

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 des fichiers .resx en fichiers .resources binaires

La conversion de fichiers .resx en fichiers de ressources binaires incorporées (.resources) présente des avantages significatifs. Bien que les fichiers .resx soient faciles à lire et à gérer pendant le développement d’applications, ils sont rarement inclus dans les applications terminées. S’ils sont distribués avec une application, ils existent en tant que fichiers distincts à l’exception de l’exécutable de l’application et de ses bibliothèques associées. En revanche, les fichiers .resources sont incorporés dans l’exécutable de l’application ou dans ses assemblys connexes. En outre, pour les applications localisées, l'utilisation de fichiers .resx pendant l'exécution place la responsabilité de la gestion du retour à des ressources alternatives sur le développeur. 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 le générateur de fichiers de ressources (resgen.exe), qui a la syntaxe de base suivante :

 resgen.exe .resxFilename

Le résultat est un fichier de ressources binaire qui a le même nom de fichier racine que le fichier .resx et une extension de fichier .resources. Ce fichier peut ensuite être compilé dans un exécutable ou une 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 d’Assembly Linker (al.exe), qui a la syntaxe de base suivante :

al resourcesFilename -out: assemblyFilename

Voir aussi