I have a resource file in a Class Library project. I'm using this resource file to hold various messages the user may end up seeing.
For example, the name of the resource is "InvalidEmailAddress" and the value in the en-US resource file is "Invalid Email Address".
When I call the ResourceManager's GetString(string) method I am doing this:
return resourceManager.GetString("InvalidEmailAddress");
However, this seems really bad to me. What if somebody changes the name of the resource? Now my statement will return a null value.
Is there a way around this issue?
UPDATE: Localization is an important factor here. The resource manager is used in order to ensure I can change the culture and get appropriate string values.
You can instead use an automatically generated class - the magic string constants will be removed from the code and replaced with strongly typed access methods. VS names this file ResourceName.Designer.cs and updates it every time resx is modified in VS.
Sample of a generated method:
internal static string String1 {
get {
return ResourceManager.GetString("String1", resourceCulture);
}
Note: while creating this file is the default behavior when you add a new resource in VS, you may have disabled it or you may have tried to use the generated resource outside the assembly. In that case, make sure to set the "Custom Tool" property or resx file to "PublicResXFileCodeGenerator" or "ResXFileCodeGenerator" (later if you use resources only inside a single assembly). (Thanks #dbaseman for comment).
When you create a Resource, it will be generated strongly typed in the Resources namespace.
You can access it by Resources.ClassName.InvalidEmailAddress where ClassName is the name of your Resource (resx) file.
Related
We have a system that manages generic physical resources. There are over 500 individual resources. The system is used for many different things and to make the software easier to write we use aliases.
For example, a physical resource TG67I9 is given an alias of "RightDoor". When code is written RightDoor is used instead of TG67I9 making the code more readable. This alias list is loaded as a text file with references to resources and their aliases. This system uses literally hundreds of different alias lists to reference the same physical resources.
This type of setup has two major shortcomings. First, when resources are called using their aliases, they are passed in as strings. Door.Open("RightDoor") for example. This does not give any tooltips or smart anything making the code more difficult to write. It basically requires constantly referencing the alias list. Is it RightDoor or Right_Door or right-door or... you get the idea. The second is that there is no validation of parameters until execution. All the compiler knows is that a string is passed in and then it's happy. Only when the code is run, the function tries to access the resource through its alias and fails because it can't find right-door because it's supposed to be RightDoor. An error is displayed. This requires tedious debugging and running the code over and over to weed out any bad aliases.
Is there a better way to do this? Such that an alias list can be made with a cross-reference of physical resources to their alias names and after the list is made that tooltips could appear suggesting resources. (Assume that a new system could be written from scratch)
I'm using the latest .NET with VisualStudio 2017 and C# to write the code.
The simplest approach is most likely a "string enum":
public class Resources {
public const string
LeftDoor = "TG67I8",
RightDoor = "TG67I9";
}
Sample use:
Door.Open(Resources.RightDoor);
Hovering over .RightDoor in VS shows a tooltip (constant) string Resources.RightDoor = "TG67I9"
Right-clicking .RightDoor and selecting Find All References will show where the variable is used.
Another option can be adding the strings in the Resources section of the Project Properties, and then:
using YourProjectNameSpace.Properties;
...
Door.Open(Resources.RightDoor);
That is a bit slower, because the resource(s) are retrieved at run-time, but allows to load the resources from a custom external file separate from the executable.
Use a static class with constants. I have done the same many times and still do. Plus .NET does this as well.
public static class PhysicalResources
{
public const string One = "Uno";
public const string Two = "Deux";
// ...
}
I followed the instructions in Put strings into resource files, instead of putting them directly in code or markup in Put UI strings into resources (except I don't understand step 4f). The structure in the Solution Explorer of the resources in my project is:
That is the hierarchy for the project's shared node. I opened the Resources1.resw file and added a couple of strings.
Then Add string resource identifiers to code and markup in that article has the following:
var loader = new Windows.ApplicationModel.Resources.ResourceLoader();
When I have that I get:
WinRT information: ResourceMap Not Found.
I have tried many other possibilities that I have found from searching but either I get that error or the class or method (in other solutions) do not exist for my project. I assume there is something relevant missing from that article.
Using C#, how do I get strings from that resources file ?
You dont need to rename your resource file. If the name of the resource file isnt the default (Resources.resw), you can add the special name in the GetForCurrentView method.
In your case the call should be:
var loader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView("Resources1.resw");
Source:GetForCurrentView(System.String)
Did you tried to specify default language in app.xaml for your actual frame?
myFrame = new Frame
{
Language = Windows.Globalization.ApplicationLanguages.Languages[0]
};
Or more specific:
Windows.Globalization.ApplicationLanguages.Languages['en']
I have a resource file strings.resx in my project that stores default English strings. For testing purpose, I created one more file strings.zh-CN.resx but the strings stored there are not real Chinese. They are just test strings that have been generated after appending some characters to the strings stored in strings.resx (main resource file). When user logs into zh-CN culture, this file helps to catch hard coded data and untranslated strings. Is it possible that I can get rid of strings.zh-CN.resx file and generate a fake resource on the fly when current thread culture is zh-CN?
Basically - are there any ways we can trick ResourceManager to return fake strings for particular cultures without having a physical .resx file?
I am using Visual Studio auto generated designer.cs file to fetch resource. I can see in designer.cs file that there is one static property for each string in .resx file. The way ResourceManager is initialized in designer.cs is as under.
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("xxx.xxx.Strings", typeof(Strings).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
This is the way static property is added by auto generated code.
/// <summary>
/// Looks up a localized string similar to Absolute.
/// </summary>
public static string Absolute {
get {
return ResourceManager.GetString("Absolute", resourceCulture);
}
}
I am looking for extension points in this retrieval. if possible I want to hook in my own custom ResourceManager (or something else I am not sure) and return a fake pseudo string when culture is zh-CN. Main purpose is I do not want to be generating a fake physical resource file just for testing purpose.
Of course you can. Do you understand how the ResourceManager works? There are multiple ways to achieve what you want. A couple are these:
ONE OPTION: Look at the code behind of a resource file. It tells you that you need to create in instance of the ResourceManager at some stage. One way to do so is to provide the name of a resource type (aka base name) and the assembly in which it can be found. Do the same! This will make you realize that you will also need a resource type (class) on the fly - so do that: create one resource type before you create an instance of the ResourceManager. The type needs to have a public property with the name of the fake string which you want to retrieve. An example how to do that is given here: Stackoverflow: Dynamically create a class in C#.
ANOTHER OPTION: Familiarize yourself with how a mock framework works such as Moq. You can apply the same idea for faking a resource type. So rather than creating a resource type on the fly you can have a resource mock which can be taught to return your _fake stri
In asp.net I use like this:
gridView_Desti.Columns["CODE_DEST"].Caption = (string) HttpContext.GetGlobalResourceObject("Client", "Code_Dest");
How can I do the same thing on WinForm ?
Client is the resource name file --> Client.resx
Code_Dest is string on Client.resx --> string Code_Dest, value Code Destinataire
You should have an auto-generated class called Resources in the Properties namespace of your project. Each resource is exposed as a property in that class.
You can do :
Client.ResourceManager.GetString("Code_Dest");
Depending on the culture, it will look for the string in Client.en-US.resx (if en-US is your current culture) and if it fail, in Client.resx.
You can also acces like this (Code_Dest must be in Client.resx) :
Client.Code_Dest;
Add new item -> Resources i.e 'Resources1.resx'
Put necessary Resources Name & value ie string resources -> 'YourResourcesName' value whatever.
Access its value with Resources1.YourResourcesName
Hope this help,
If you don't have the namespace in, then prepend with "Properties" C# as so:
Properties.Resources1.YourResourcesName
Makes your code so much cleaner using the resx file. As an example, I have a DataGridViewImageColumn and assigned an image to it (from VS Image Library - the image is a .png file):
colAddNewItem.Image = Properties.Resource1.Add_16x;
FYI, in VB.Net it's
Resources.Resources1.YourResourcesName
There are many other ways, but this is the simplest, cleanest & preferred method.
I have a "settings file" in my Winforms application called Settings.settings with a partial class for custom methods, etc. Is there a way to load / save dynamic settings based on arbitrary keys?
For example, I have some ListViews in my application in which I want to save / load the column widths; Instead of creating a width setting for each column for each list view I would like a simple method to load / save the widths automatically.
Below is an example of the save method I have tried:
internal sealed partial class Settings
{
public void SetListViewColumnWidths(ListView listView)
{
String baseKey = listView.Name;
foreach (ColumnHeader h in listView.Columns)
{
String key = String.Format("{0}-{1}", baseKey, h.Index);
this[key] = h.Width;
}
}
}
When running that code I get the error "The settings property 'TestsListView-0' was not found." Is there something I am missing?
Store your column width settings in an Xml Serializable object. Ie, something that implements IXmlSerializable then create a single setting entry of that type in Settings.settings.
A good option would probably be an Xml Serializable Dictionary. A quick google search found quite a few different blog posts that describe how to implement that.
As mentioned in other answers you'll need to ensure that this object is a User setting. You may also need to initialize the setting instance. Ie, create a XmlSerializableDictionary() instance and assign it to the setting if the setting is null. The settings subsystem doesn't create default instances of complex setting objects.
Also, if you want these settings to persist between assembly versions (ie, be upgradable) you will need to upgrade the settings on application startup. This is described in detail on Miha Markič's blog and Raghavendra Prabhu's blog.
I think the error
The settings property
'key' was not found.
occurs because the 'key' value does not exist in your settings file (fairly self-explanatory).
As far as I am aware, you can't add settings values programmatically, you might need to investigate adding all of the settings you need to the file after all, although once they are there, I think you'll be able to use the sort of code you've given to save changes.
To Save changes, you'll need to make sure they are 'User' settings, not 'Application'.
The Settings file is quite simple XML, so you might be able to attack the problem by writing the XML directly to the file, but I've never done it, so can't be sure it would work, or necessarily recommend that approach.
http://msdn.microsoft.com/en-us/library/cftf714c.aspx is the MSDN link to start with.
You can do Settings.Save() or similar on user settings, but note that such settings would NOT get persisted to the xxx.exe.config file in your app directory as you'd expect. They actually go somewhere deep inside the user folder (search your drive for xxx.exe.config to find it). Next time that you manually change xxx.exe.config in your app directory, the change will mysteriously not apply (the system is still using the saved one from the user directory).