Modifica del file .resx in C #

Ho un file .resx che contiene coppie nome-valore (entrambe le stringhe). Ora voglio modificare i valori in alcune coppie nome-valore programmaticamente usando C #. Come posso ottenerlo?

C’è un intero spazio dei nomi per la gestione delle risorse: System.Resources. Scopri la class ResourceManager, ResXResourceReader e ResXResourceWriter.

http://msdn.microsoft.com/en-us/library/system.resources.aspx


Sono riuscito a mettere le mani su un metodo di debug molto vecchio che usavo a un certo punto quando stavo testando alcune cose relative alle risorse. Questo dovrebbe fare il trucco per te.

 public static void UpdateResourceFile(Hashtable data, String path) { Hashtable resourceEntries = new Hashtable(); //Get existing resources ResXResourceReader reader = new ResXResourceReader(path); if (reader != null) { IDictionaryEnumerator id = reader.GetEnumerator(); foreach (DictionaryEntry d in reader) { if (d.Value == null) resourceEntries.Add(d.Key.ToString(), ""); else resourceEntries.Add(d.Key.ToString(), d.Value.ToString()); } reader.Close(); } //Modify resources here... foreach (String key in data.Keys) { if (!resourceEntries.ContainsKey(key)) { String value = data[key].ToString(); if (value == null) value = ""; resourceEntries.Add(key, value); } } //Write the combined resource file ResXResourceWriter resourceWriter = new ResXResourceWriter(path); foreach (String key in resourceEntries.Keys) { resourceWriter.AddResource(key, resourceEntries[key]); } resourceWriter.Generate(); resourceWriter.Close(); } 

Se si desidera mantenere i commenti esistenti nei file di risorse, utilizzare questo (in base al codice di SirMoreno modificato)

  public static void UpdateResourceFile(Hashtable data, String path) { Hashtable resourceEntries = new Hashtable(); //Get existing resources ResXResourceReader reader = new ResXResourceReader(path); reader.UseResXDataNodes = true; ResXResourceWriter resourceWriter = new ResXResourceWriter(path); System.ComponentModel.Design.ITypeResolutionService typeres = null; if (reader != null) { IDictionaryEnumerator id = reader.GetEnumerator(); foreach (DictionaryEntry d in reader) { //Read from file: string val = ""; if (d.Value == null) resourceEntries.Add(d.Key.ToString(), ""); else { val = ((ResXDataNode)d.Value).GetValue(typeres).ToString(); resourceEntries.Add(d.Key.ToString(), val); } //Write (with read to keep xml file order) ResXDataNode dataNode = (ResXDataNode)d.Value; //resourceWriter.AddResource(d.Key.ToString(), val); resourceWriter.AddResource(dataNode); } reader.Close(); } //Add new data (at the end of the file): Hashtable newRes = new Hashtable(); foreach (String key in data.Keys) { if (!resourceEntries.ContainsKey(key)) { String value = data[key].ToString(); if (value == null) value = ""; resourceWriter.AddResource(key, value); } } //Write to file resourceWriter.Generate(); resourceWriter.Close(); } 
  public static void AddOrUpdateResource(string key, string value) { var resx = new List(); using (var reader = new ResXResourceReader(resourceFilepath)) { resx = reader.Cast().ToList(); var existingResource = resx.Where(r => r.Key.ToString() == key).FirstOrDefault(); if (existingResource.Key == null && existingResource.Value == null) // NEW! { resx.Add(new DictionaryEntry() { Key = key, Value = value }); } else // MODIFIED RESOURCE! { var modifiedResx = new DictionaryEntry() { Key = existingResource.Key, Value = value }; resx.Remove(existingResource); // REMOVING RESOURCE! resx.Add(modifiedResx); // AND THEN ADDING RESOURCE! } } using (var writer = new ResXResourceWriter(ResxPathEn)) { resx.ForEach(r => { // Again Adding all resource to generate with final items writer.AddResource(r.Key.ToString(), r.Value.ToString()); }); writer.Generate(); } } 

Womp ha capito bene (10x).

Ma ecco un codice che mantiene l’ordine dei file XML, aggiungi nuovi alla fine del file. (per il controllo del codice sorgente)

  //Need dll System.Windows.Forms public static void UpdateResourceFile(Hashtable data, String path) { Hashtable resourceEntries = new Hashtable(); //Get existing resources ResXResourceReader reader = new ResXResourceReader(path); ResXResourceWriter resourceWriter = new ResXResourceWriter(path); if (reader != null) { IDictionaryEnumerator id = reader.GetEnumerator(); foreach (DictionaryEntry d in reader) { //Read from file: string val = ""; if (d.Value == null) resourceEntries.Add(d.Key.ToString(), ""); else { resourceEntries.Add(d.Key.ToString(), d.Value.ToString()); val = d.Value.ToString(); } //Write (with read to keep xml file order) resourceWriter.AddResource(d.Key.ToString(), val); } reader.Close(); } //Add new data (at the end of the file): Hashtable newRes = new Hashtable(); foreach (String key in data.Keys) { if (!resourceEntries.ContainsKey(key)) { String value = data[key].ToString(); if (value == null) value = ""; resourceWriter.AddResource(key, value); } } //Write to file resourceWriter.Generate(); resourceWriter.Close(); } 

Questa è la mia versione basata su Ers ‘e basata sul codice di SirMoreno. Solo un po ‘più corto. Questo non è ancora un metadati gestibile che è ansible ma non necessario per me.

  public static bool AddToResourceFile(string key, string value, string comment, string path) { using (ResXResourceWriter resourceWriter = new ResXResourceWriter(path)) { //Get existing resources using (ResXResourceReader reader = new ResXResourceReader(path) { UseResXDataNodes = true }) { foreach (DictionaryEntry resEntry in reader) { ResXDataNode node = resEntry.Value as ResXDataNode; if (node == null) continue; if (string.CompareOrdinal(key, node.Name) == 0) { // Keep resources untouched. Alternativly modify this resource. return false; } resourceWriter.AddResource(node); } } //Add new data (at the end of the file): resourceWriter.AddResource(new ResXDataNode(key, value) { Comment = comment }); //Write to file resourceWriter.Generate(); } return true; } 

La risposta di Womp è stata migliorata – senza Hashtable obsoleto, controllando se il file esiste e usando LINQ:

  public static void UpdateResourceFile(Dictionary data, string path) { Dictionary resourceEntries = new Dictionary(); if (File.Exists(path)) { //Get existing resources ResXResourceReader reader = new ResXResourceReader(path); resourceEntries = reader.Cast().ToDictionary(d => d.Key.ToString(), d => d.Value?.ToString() ?? ""); reader.Close(); } //Modify resources here... foreach (KeyValuePair entry in data) { if (!resourceEntries.ContainsKey(entry.Key)) { if (!resourceEntries.ContainsValue(entry.Value)) { resourceEntries.Add(entry.Key, entry.Value); } } } string directoryPath = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(directoryPath)) { Directory.CreateDirectory(directoryPath); } //Write the combined resource file ResXResourceWriter resourceWriter = new ResXResourceWriter(path); foreach (KeyValuePair entry in resourceEntries) { resourceWriter.AddResource(entry.Key, resourceEntries[entry.Key]); } resourceWriter.Generate(); resourceWriter.Close(); } 

Tutte le altre risposte fanno uso di ResXResourceWriter, ma per alcuni casi speciali può essere fattibile e meglio lavorare semplicemente con il file Resources.resx come documento XML.

Ho una situazione specifica in cui voglio manipolare le voci Resources.resx per un insieme di file di icone. Ci possono essere fino a diverse centinaia di voci, e posso contare su tutte che sembrano esattamente così:

   ..\..\..\..\..\..\Icons\Incors-workplace2-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a  

Ho provato a usare ResXResourceWriter e ResXResourceReader per questo programma, ma alla fine ho aperto i vari file Resources.resx come documenti XML e li ho manipolati in quel modo. L’intero programma è troppo grande (e troppo specifico per le applicazioni) per postare qui, ma pubblicherò alcuni ceppi di codice per mostrare alcune delle tecniche che possono essere utilizzate.

  ///  /// Method to load a Resources.resx file (if it exists) as an XML Document object. ///  private static XmlDocument LoadResourcesResx(string projectPath) { string fileName = projectPath + @"Properties\Resources.resx"; if (!File.Exists(fileName)) return null; XmlDocument xdResx = new XmlDocument(); xdResx.Load(fileName); return xdResx; } // --------------------------------------------------------------------------- ///  /// Method to fix the names of any resources that contain '-' instead of '_'. ///  private static void FixResourceNames(XmlDocument xdResx, ref bool resxModified) { // Loop for all of the  elements that have name= attributes (node = "name" attr.) XmlNodeList xnlDataElements = xdResx.SelectNodes("/root/data/@name"); if (xnlDataElements != null) { foreach (XmlNode xmlNode in xnlDataElements) { // Modify the name= attribute if necessary string oldDataName = xmlNode.Value; string newDataName = oldDataName.Replace('-', '_'); if (oldDataName != newDataName) { xmlNode.Value = newDataName; resxModified = true; } } } } // --------------------------------------------------------------------------- // Prepare to add resource nodes to client-basic's Resources.resx file XmlNode rootNodeBasic = xdResx.SelectSingleNode("/root"); // --------------------------------------------------------------------------- ///  /// Sub-method of above method (not included here) to copy a new icon usage from one of the client-maxi projects /// to the client-basic project. ///  private static bool CopyIconToClientBasic(string projectPath, XmlDocument xdResxBasic, XmlNode rootNodeBasic, XmlNode xmlNodeMaxi) { // Check if this is an icon-based resource, and get the resource name if so string oldDataName = GetAndCheckResourceName(xmlNodeMaxi); if (oldDataName == null) return false; // Determine if there is a 16x16, 20x20, 24x24, 32x32 or 48x48 version of this icon // available, picking the lowest size to reduce client-basic assembly increase for a // resource which will probably never be used string oldFileName = xmlNodeMaxi.FirstChild.InnerText.Split(';')[0]; string minSize = FindMinimumIconSize(projectPath, oldFileName); // Not included here if (minSize == null) return false; // Something wrong, can't find icon file // Test if client-basic's resources includes a version of this icon for smallest size string newDataName = oldDataName.Remove(oldDataName.Length - 5) + minSize; if (xdResxBasic.SelectSingleNode("/root/data[@name='" + newDataName + "']") != null) return false; // Already in client-basic // Add the smallest available size version of this icon to the client-basic project string oldSize = oldDataName.Substring(oldDataName.Length - 5); // "16x16", "20x20" XmlNode newNodeBasic = xdResxBasic.ImportNode(xmlNodeMaxi, true); if (newNodeBasic.Attributes != null) newNodeBasic.Attributes["name"].Value = newDataName; // Maybe force smaller size newNodeBasic.FirstChild.InnerText = newNodeBasic.FirstChild.InnerText.Replace(oldSize, minSize); rootNodeBasic.AppendChild(newNodeBasic); return true; } // --------------------------------------------------------------------------- ///  /// Method to filter out non-icon resources and return the resource name for the icon-based /// resource in the Resources.resx object. ///  /// name of resource, ie, name= value, or null if not icon resource private static string GetAndCheckResourceName(XmlNode xmlNode) { // Ignore resources that aren't PNG-based icon files with a standard size. This // includes ignoring ICO-based resources. if (!xmlNode.FirstChild.InnerText.Contains(";System.Drawing.Bitmap,")) return null; if (xmlNode.Attributes == null) return null; string dataName = xmlNode.Attributes["name"].Value; if (dataName.EndsWith("_16x16", StringComparison.Ordinal) || dataName.EndsWith("_20x20", StringComparison.Ordinal) || dataName.EndsWith("_24x24", StringComparison.Ordinal) || dataName.EndsWith("_32x32", StringComparison.Ordinal) || dataName.EndsWith("_48x48", StringComparison.Ordinal)) return dataName; return null; } // --------------------------------------------------------------------------- // It's too messy to create a new node from scratch when not using the ResXResourceWriter // facility, so we cheat and clone an existing icon entry, the one for Cancel buttons // Get the Cancel icon name and filename BuiltInIcon cancelIcon = BuiltInIconNames.FindIconByName(BuiltInIconNames.CCancel); string cancelIconResourceName = cancelIcon.ResourceName + "_16x16"; // Find it in the Resources.resx file - it should be there XmlNode cancelIconNode = xdResxBasic.SelectSingleNode("/root/data[@name='" + cancelIconResourceName + "']"); if (cancelIconNode == null) { PreprocessorMain.DisplayError(0x27b699fu, "Icon " + cancelIconResourceName + " not found in Resources.resx file."); return false; } // Make a clone of this node in the Resources.resx file XmlNode newNode = cancelIconNode.Clone(); if (newNode.Attributes == null) // Not possible? { PreprocessorMain.DisplayError(0x27b8038u, "Node for icon " + cancelIconResourceName + " not as expected in Resources.resx file."); return false; } // Modify the cloned XML node to represent the desired icon file/resource and add it to the // Resources.resx file newNode.Attributes["name"].Value = iconResourceName; newNode.InnerText = newNode.InnerText.Replace(cancelIcon.FileNameNoSize + "-16x16.png", iconFileName); rootNodeBasic.AppendChild(newNode); resxModified = true;