I have problem with my localized attributes such as:
public class LocalizedDisplayNameAttribute : DisplayNameAttribute
{
public LocalizedDisplayNameAttribute(string resourceId)
: base(GetMessageFromResource(resourceId))
{ }
private static string GetMessageFromResource(string resourceId)
{
var propertyInfo = typeof(Lockit).GetProperty(resourceId, BindingFlags.Static | BindingFlags.Public);
return (string)propertyInfo.GetValue(null, null);
}
}
When I'm using properties with this attribute it's localized in PropertyGrid, but when I change the current CultureInfo it doesn't refresh, even if I create this PropertyGrid again. I've try to manually call this attribute by:
foreach (PropertyInfo propertyInfo in myPropertiesInfoTab)
{
object[] custom_attributes = propertyInfo.GetCustomAttributes(false);
}
The property constructor is called, but the newly created PropertyGrid still has the property for the old culture display name (always the same value as first created).
It works when I restarting application, but I don't want to do this. Is there any solution?
We can reproduce this in a simple but complete example (that simply adds a counter onto the name, to represent each translation as it happens):
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Show();
Show();
}
static void Show()
{
using(var grid = new PropertyGrid
{Dock = DockStyle.Fill, SelectedObject = new Foo { Bar = "def"} })
using(var form = new Form { Controls = { grid }})
{
form.ShowDialog();
}
}
class Foo
{
[CheekyDisplayName("abc")]
public string Bar { get; set; }
}
public class CheekyDisplayNameAttribute : DisplayNameAttribute
{
public CheekyDisplayNameAttribute(string resourceId)
: base(GetMessageFromResource(resourceId))
{ }
private static string GetMessageFromResource(string resourceId)
{
return resourceId + Interlocked.Increment(ref counter);
}
private static int counter;
}
This demonstrates that the attribute is being cached between calls. Perhaps the easiest way to fix this is to delay the translation to the time that DisplayName
is queried:
public class CheekyDisplayNameAttribute : DisplayNameAttribute
{
public CheekyDisplayNameAttribute(string resourceId)
: base(resourceId)
{ }
private static string GetMessageFromResource(string resourceId)
{
return resourceId + Interlocked.Increment(ref counter);
}
public override string DisplayName
{
get { return GetMessageFromResource(base.DisplayName); }
}
private static int counter;
}
However, note that this can be called lots of times (36 per showing); you might want to cache the value along with the culture it was cached for:
private CultureInfo cachedCulture;
private string cachedDisplayName;
public override string DisplayName
{
get
{
var culture = CultureInfo.CurrentCulture;
if (culture != cachedCulture)
{
cachedDisplayName = GetMessageFromResource(base.DisplayName);
cachedCulture = culture;
}
return cachedDisplayName;
}
}