Tôi có tệp .resx
chứa cặp giá trị tên chuỗi. Bây giờ tôi muốn sửa đổi các giá trị trong một số cặp giá trị tên nhất định bằng cách sử dụng C#. Làm thế nào tôi có thể đạt được điều đó.Sửa đổi tệp .resx trong C#
Xin cảm ơn trước.
Tôi có tệp .resx
chứa cặp giá trị tên chuỗi. Bây giờ tôi muốn sửa đổi các giá trị trong một số cặp giá trị tên nhất định bằng cách sử dụng C#. Làm thế nào tôi có thể đạt được điều đó.Sửa đổi tệp .resx trong C#
Xin cảm ơn trước.
Có toàn bộ không gian tên để quản lý tài nguyên: System.Resources. Kiểm tra lớp ResourceManager, cũng như ResXResourceReader và ResXResourceWriter.
http://msdn.microsoft.com/en-us/library/system.resources.aspx
tôi quản lý để đặt tay của tôi trên một phương pháp debug rất cũ mà tôi sử dụng để sử dụng tại một thời điểm khi tôi đã được thử nghiệm một số công cụ tài nguyên liên quan. Điều này nên làm các trick cho bạn.
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();
}
Đây có phải là cách duy nhất để CẬP NHẬT một kvp trong một tệp resx không? Có vẻ như nó sẽ chỉ thêm một kvp khác vào tệp. – dotnetN00b
Vấn đề là bạn sẽ mất các bình luận tài nguyên nếu điều đó quan trọng đối với bạn. – uli78
Làm đúng (10x).
Nhưng đây là mã giữ thứ tự tệp XML, thêm mới ở cuối tệp. (đối với kiểm soát nguồn)
//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();
}
Nếu bạn muốn giữ lại các ý kiến tồn tại trong tập tin tài nguyên sau đó sử dụng này (Dựa trên mã SirMoreno của sửa đổi)
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<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();
}
}
Thật sự rất hữu ích Cám ơn Rất nhiều :) 1 tôi muốn tôi là chủ sở hữu của câu hỏi này tôi đánh dấu của bạn là một trong những quyền :)) cảm ơn một lần nữa – Marwan
Rất hữu ích, Cảm ơn bạn rất nhiều –
Đây là phiên bản của tôi dựa trên Ers 'và dựa trên mã của SirMoreno. Chỉ một chút ngắn hơn. Điều này vẫn chưa được xử lý metaData mà có thể nhưng không cần thiết cho tôi.
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;
}
này được cải thiện câu trả lời Womp của - mà không lỗi thời Hashtable, kiểm tra nếu tập tin tồn tại và sử dụng 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();
}
Tất cả các câu trả lời khác tận dụng ResXResourceWriter, nhưng đối với một số trường hợp đặc biệt nó có thể khả thi và tốt hơn là chỉ cần làm việc với tệp Resources.resx dưới dạng tài liệu XML.
Tôi có một tình huống cụ thể nơi tôi muốn thao tác các mục Resources.resx cho một tập hợp các tệp biểu tượng. Có thể lên đến vài trăm mục, và tôi có thể tin tưởng vào tất cả chúng tìm kiếm chính xác như thế này:
<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>
tôi đã cố gắng sử dụng ResXResourceWriter và ResXResourceReader cho chương trình này, nhưng tôi đã kết thúc thay vì mở các tập tin khác nhau Resources.resx dưới dạng tài liệu XML và thao tác chúng theo cách đó. Toàn bộ chương trình là quá lớn (và quá cụ thể cho ứng dụng) để đăng ở đây, nhưng tôi sẽ đăng một vài đoạn mã để hiển thị một số kỹ thuật có thể được sử dụng.
/// <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;
Tôi rất muốn nghe (các) trường hợp sử dụng cho việc này. Tôi có một khách hàng muốn sửa đổi tài nguyên khi đang bay, nhưng mọi thứ về điều này có vẻ không tự nhiên và chống lại các mục đích của các tệp tài nguyên. – MrBoJangles