2009-03-24 31 views
21

.resxファイルに文字列名の値のペアが含まれていました。今度は、特定の名前の値のペアの値をプログラムでC#を使用して変更したいと思います。どうすればそれを達成できますか?Cでの.resxファイルの変更#

ありがとうございます。

+0

私はこのためのユースケースを聞いて興味があります。その場でリソースを変更したいクライアントがいますが、これに関するすべてが不自然で、リソースファイルの目的に反するようです。 – MrBoJangles

答えて

25

リソース管理の名前空間はすべてSystem.Resourcesです。 ResourceManagerクラス、ResXResourceReader、およびResXResourceWriterを確認してください。

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


私はいくつかのリソース関連のものをテストしていた時に1ポイントで使用するために使用される非常に古いデバッグ方法で私の手を置くことができました。これはあなたのためのトリックを行う必要があります。

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(); 

    } 
+1

これはresxファイルのkvpを更新する唯一の方法ですか?それはちょうどファイルに別のkvpを追加するように思えます。 – dotnetN00b

+0

問題は、それが重要である場合、リソースのコメントを失うことです。 – uli78

4

Wompは正しい(10倍)。

ただし、XMLファイルの順序を保持するコードは、ファイルの最後に新しいコードを追加します。

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(); 

    } 
9

(ソース制御のために)これは私のバージョンに基づいていますSirMorenoのコードに基づいています。ほんの少し短く。これはまだ可能ですが、私のために必要ではないメタデータをハンドリングしていません。

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; 
    } 
9
public static void AddOrUpdateResource(string key, string value) 
    { 
     var resx = new List<DictionaryEntry>(); 
     using (var reader = new ResXResourceReader(resourceFilepath)) 
     { 
      resx = reader.Cast<DictionaryEntry>().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(); 
     } 
    } 
+1

Realy Usefullありがとうございました:) +1私はこの質問の所有者でありたいと思っています。あなたのことは正しいです:))ありがとうagain – Marwan

+0

非常に便利です、ありがとう –

0

あなたがして(SirMorenoのコード変更に基づいて)これを使用するリソースファイルに既存のコメントを残しておきたい場合は

//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(); 

    } 
0

これはWompの答えを改善している - 時代遅れのHashtableせずに、ファイルが存在するかどうかをチェックし、LINQを使用して:

public static void UpdateResourceFile(Dictionary<string, string> data, string path) 
    { 
     Dictionary<string, string> resourceEntries = new Dictionary<string, string>(); 
     if (File.Exists(path)) 
     { 
      //Get existing resources 
      ResXResourceReader reader = new ResXResourceReader(path); 
      resourceEntries = reader.Cast<DictionaryEntry>().ToDictionary(d => d.Key.ToString(), d => d.Value?.ToString() ?? ""); 
      reader.Close(); 
     } 

     //Modify resources here... 
     foreach (KeyValuePair<string, string> 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<string, string> entry in resourceEntries) 
     { 
      resourceWriter.AddResource(entry.Key, resourceEntries[entry.Key]); 
     } 
     resourceWriter.Generate(); 
     resourceWriter.Close(); 
    } 
0

他の回答のすべてがResXResourceWriterを利用するが、ある特別な場合のためにそれであってもよいですXML文書としてResources.resxファイルを使用するだけで簡単に実行できます。

アイコンファイルのセットのResources.resxエントリを操作する特定の状況があります。そこから数百のエントリまでであり得る、と私はすべて、まさにこのように見て彼らに数えることができます。私はこのプログラムのためにResXResourceWriterとResXResourceReaderを使用してみましたが、私が代わりに様々なResources.resxファイルを開くことになった

<data name="Incors_workplace2_16x16" type="System.Resources.ResXFileRef, System.Windows.Forms"> 
    <value>..\..\..\..\..\..\Icons\Incors-workplace2-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> 
    </data> 

XMLドキュメントとして扱い、そのように操作します。プログラム全体がここに投稿するには大きすぎます(そしてアプリケーション固有のものもあります)が、私はいくつかのテクニックを示すためにコードをいくつか紹介します。

 /// <summary> 
     /// Method to load a Resources.resx file (if it exists) as an XML Document object. 
     /// </summary> 
     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; 
     } 

    // --------------------------------------------------------------------------- 


     /// <summary> 
     /// Method to fix the names of any resources that contain '-' instead of '_'. 
     /// </summary> 
     private static void FixResourceNames(XmlDocument xdResx, ref bool resxModified) 
     { 
     // Loop for all of the <data> 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"); 
    // --------------------------------------------------------------------------- 

     /// <summary> 
     /// 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. 
     /// </summary> 
     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; 
     } 

    // --------------------------------------------------------------------------- 

     /// <summary> 
     /// Method to filter out non-icon resources and return the resource name for the icon-based 
     /// resource in the Resources.resx object. 
     /// </summary> 
     /// <returns>name of resource, i.e., name= value, or null if not icon resource</returns> 
     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; 
関連する問題