Práce se soubory .resx programově

Vzhledem k tomu, že soubory prostředků XML (.resx) musí obsahovat dobře definovaný XML, včetně hlavičky, která musí dodržovat konkrétní schéma následované daty v párech název/hodnota, můžete zjistit, že ruční vytváření těchto souborů je náchylné k chybám. Alternativně můžete soubory .resx vytvářet programově pomocí typů a členů v knihovně tříd .NET. Knihovnu tříd .NET můžete použít také k načtení prostředků uložených v souborech .resx. Tento článek vysvětluje, jak můžete používat typy a členy v oboru názvů System.Resources pro práci se soubory .resx.

Tento článek popisuje práci se soubory XML (.resx), které obsahují prostředky. Informace o práci s binárními soubory prostředků, které byly vloženy do sestavení, najdete v tématu ResourceManager .

Upozornění

Existují také jiné způsoby, jak pracovat se soubory .resx než prostřednictvím kódu programu. Když přidáte soubor prostředků do projektu Visual Studio, poskytuje Visual Studio rozhraní pro vytvoření a údržbu souboru .resx a automaticky převede soubor .resx na soubor .resources v době kompilace. Textový editor můžete použít také k přímé manipulaci se souborem .resx. Pokud se ale chcete vyhnout poškození souboru, dávejte pozor, abyste neupravovat žádné binární informace uložené v souboru.

Vytvoření souboru .resx

Pomocí třídy System.Resources.ResXResourceWriter můžete programově vytvořit soubor .resx pomocí následujících kroků:

  1. Vytvořte instanci objektu voláním metody a poskytnutím názvu souboru ResXResourceWriter ResXResourceWriter(String) .resx. Název souboru musí obsahovat příponu .resx. Pokud vytváříte instanci objektu v bloku, není explicitně nutné volat ResXResourceWriter using ResXResourceWriter.Close metodu v kroku 3.

  2. Pro každý prostředek, který chcete přidat do ResXResourceWriter.AddResource souboru, volejte metodu . Přetížení této metody slouží k přidání řetězcových, objektových a binárních dat (pole bajtů). Pokud je prostředek objekt, musí být serializovatelný.

  3. Voláním ResXResourceWriter.Close metody vygeneruje soubor prostředků a uvolní všechny prostředky. Pokud byl objekt vytvořen v rámci bloku, prostředky se zapisují do souboru ResXResourceWriter .resx a prostředky používané objektem jsou uvolněny using ResXResourceWriter na konci using bloku.

Výsledný soubor .resx má odpovídající hlavičku a značku pro každý prostředek data přidaný ResXResourceWriter.AddResource metodou .

Upozornění

Nepoužívejte soubory prostředků k ukládání hesel, informací citlivých na zabezpečení nebo soukromých dat.

Následující příklad vytvoří soubor .resx s názvem CarResources.resx, který ukládá šest řetězců, ikonu a dva objekty definované aplikací (dva Automobile objekty). Třída , která je definována a Automobile vytvořena instance v příkladu, je označena SerializableAttribute atributem .

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

Tip

Soubory .resx Visual Studio také použít k vytvoření souborů .resx. V době kompilace používá Visual Studio generátor souborů prostředků (Resgen.exe) k převodu souboru .resx na binární soubor prostředků (.resources) a také ho vloží do sestavení aplikace nebo satelitního sestavení.

Soubor .resx nelze vložit do spustitelného souboru modulu runtime nebo ho zkompilovat do satelitního sestavení. Soubor .resx musíte převést na binární soubor prostředků (.resources) pomocí generátoru souborů prostředků (Resgen.exe). Výsledný soubor .resources lze poté vložit do sestavení aplikace nebo satelitního sestavení. Další informace najdete v tématu Vytvoření souborů prostředků.

Zobrazení výčtu prostředků

V některých případech můžete chtít ze souboru .resx načíst všechny prostředky místo konkrétního prostředku. Chcete-li to provést, můžete použít System.Resources.ResXResourceReader třídu , která poskytuje enumerátor pro všechny prostředky v souboru .resx. Třída System.Resources.ResXResourceReader implementuje IDictionaryEnumerator , který vrací DictionaryEntry objekt, který představuje konkrétní prostředek pro každou iteraci smyčky. Jeho vlastnost vrátí klíč prostředku a DictionaryEntry.Key jeho vlastnost vrátí hodnotu DictionaryEntry.Value prostředku.

Následující příklad vytvoří objekt pro soubor CarResources.resx vytvořený v předchozím příkladu a ResXResourceReader iteruje souborem prostředků. Přidá dva objekty, které jsou definovány v souboru prostředků, do objektu a přidá pět ze Automobile System.Collections.Generic.List<T> šesti řetězců do SortedList objektu. Hodnoty v objektu jsou převedeny na pole parametrů, které slouží k zobrazení záhlaví sloupců SortedList v konzole. Hodnoty Automobile vlastností se také zobrazí v konzole.

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

Načtení konkrétního prostředku

Kromě výčtu položek v souboru .resx můžete načíst konkrétní prostředek podle názvu pomocí System.Resources.ResXResourceSet třídy . Metoda ResourceSet.GetString(String) načte hodnotu pojmenovaného řetězcového prostředku. Metoda načte hodnotu pojmenovaného objektu nebo ResourceSet.GetObject(String) binárních dat. Metoda vrátí objekt, který musí být poté přetypován (v jazyce C#) nebo převeden (Visual Basic) na objekt odpovídajícího typu.

Následující příklad načte řetězec titulku formuláře a ikonu podle názvů prostředků. Načte také objekty definované aplikací použité v předchozím Automobile příkladu a zobrazí je v ovládacím DataGridView prvku.

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

Převod souborů .resx na binární soubory .resources

Převod souborů .resx na soubory vloženého binárního prostředku (.resources) má významné výhody. I když se soubory .resx snadno čtou a udržují během vývoje aplikací, jsou zřídka součástí hotových aplikací. Pokud jsou distribuovány s aplikací, existují jako samostatné soubory kromě spustitelného souboru aplikace a doprovodných knihoven. Naopak soubory .resources jsou vloženy do spustitelného souboru aplikace nebo do doprovodných sestavení. Kromě toho u lokalizovaných aplikací spoléhání na soubory .resx za běhu klade odpovědnost za zpracování záložních prostředků na vývojáře. Naopak pokud byla vytvořena sada satelitních sestavení obsahujících vložené soubory .resources, modul CLR (Common Language Runtime) zpracuje záložní proces prostředků.

Pokud chcete převést soubor .resx na soubor .resources, použijte generátor souborů prostředků (resgen.exe),který má následující základní syntaxi:

 resgen.exe .resxFilename

Výsledkem je binární soubor prostředků, který má stejný název kořenového souboru jako soubor .resx a příponu souboru .resources. Tento soubor je pak možné zkompilovat do spustitelného souboru nebo knihovny v době kompilace. Pokud používáte kompilátor Visual Basic, použijte následující syntaxi pro vložení souboru .resources do spustitelného souboru aplikace:

vbc filename .vb -resource: .resourcesFilename

Pokud používáte jazyk C#, syntaxe je následující:

 csc filename .cs -resource: .resourcesFilename

Soubor .resources lze také vložit do satelitního sestavení pomocí linkeru sestavení (al.exe),který má následující základní syntaxi:

al resourcesFilename -out: assemblyFilename

Viz také