.resx
ファイルに文字列名の値のペアが含まれていました。今度は、特定の名前の値のペアの値をプログラムでC#を使用して変更したいと思います。どうすればそれを達成できますか?Cでの.resxファイルの変更#
ありがとうございます。
.resx
ファイルに文字列名の値のペアが含まれていました。今度は、特定の名前の値のペアの値をプログラムでC#を使用して変更したいと思います。どうすればそれを達成できますか?Cでの.resxファイルの変更#
ありがとうございます。
リソース管理の名前空間はすべて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();
}
これはresxファイルのkvpを更新する唯一の方法ですか?それはちょうどファイルに別のkvpを追加するように思えます。 – dotnetN00b
問題は、それが重要である場合、リソースのコメントを失うことです。 – uli78
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();
}
(ソース制御のために)これは私のバージョンに基づいています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;
}
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();
}
}
Realy Usefullありがとうございました:) +1私はこの質問の所有者でありたいと思っています。あなたのことは正しいです:))ありがとうagain – Marwan
非常に便利です、ありがとう –
あなたがして(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();
}
これは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();
}
他の回答のすべてが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;
私はこのためのユースケースを聞いて興味があります。その場でリソースを変更したいクライアントがいますが、これに関するすべてが不自然で、リソースファイルの目的に反するようです。 – MrBoJangles