C# 资源文件中的 WinForms 字符串,在设计器中连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1843051/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WinForms strings in resource files, wired up in designer
提问by Danny Tuppeny
I'm trying to localise a WinForms app for multiple languages. I'm trying to find a way to set my form labels/buttons text properties to read from the resources file in the designer (rather than having to maintain a chunk of code that sets them programatically).
我正在尝试为多种语言本地化 WinForms 应用程序。我试图找到一种方法来设置我的表单标签/按钮文本属性以从设计器中的资源文件中读取(而不是必须维护一段以编程方式设置它们的代码)。
I've found I can set form.Localizable=true, but then the resources are read from a file alongside the form, but many of mine are shared across multiple forms.
我发现我可以设置 form.Localizable=true,但是随后资源是从表单旁边的文件中读取的,但是我的许多资源是跨多个表单共享的。
Is there any way to set a label's text in the designer, to a value stored in a project-level resx file?
有什么方法可以将设计器中的标签文本设置为存储在项目级 resx 文件中的值?
采纳答案by Jon Seigel
To answer the question, no.
要回答这个问题,没有。
But IMO, this should not be done anyways if the text will be static.
但是 IMO,如果文本是静态的,无论如何都不应该这样做。
Have a read at my answers on localization and resources:
Resource string location
Globalize an existing Windows Forms application
Using .resx files for global application messages
阅读我关于本地化和资源的回答:
资源字符串位置
全球化现有的 Windows 窗体应用程序
使用 .resx 文件获取全局应用程序消息
回答by Brian
The only way I can think of would be to create a custom control that would add a property for the resource name. When the property is set, grab the value from the project resource file and set the text property with it. You will want to make sure that Text doesn't get serialized or it might overwrite the value set by ResourceName.
我能想到的唯一方法是创建一个自定义控件,为资源名称添加属性。设置属性后,从项目资源文件中获取值并使用它设置文本属性。您需要确保 Text 不会被序列化,否则它可能会覆盖 ResourceName 设置的值。
public class ResourceLabel
: Label
{
private string mResourceName;
public string ResourceName
{
get { return mResourceName; }
set
{
mResourceName = value;
if (!string.IsNullOrEmpty(mResourceName))
base.Text = Properties.Resources.ResourceManager.GetString(mResourceName);
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get { return base.Text; }
set
{
// Set is done by resource name.
}
}
}
回答by Isti115
I think I found a way to do this!
我想我找到了一种方法来做到这一点!
First in your Resources.resx set the Access Modifier to Public.
首先在您的 Resources.resx 中将访问修饰符设置为公共。
After that in the designer generated code (Form.Designer.cs) you can write this to the appropriate control:
之后,在设计器生成的代码 (Form.Designer.cs) 中,您可以将其写入适当的控件:
this.<control>.Text = Properties.Resources.<stringname>
for example:
例如:
this.footerLabel.Text = Properties.Resources.footerString;
ps.:I don't know how ethical this solution is, but it works!
ps.:我不知道这个解决方案有多合乎道德,但它有效!
回答by Walter Vehoeven
Easy enough to implement, by the way, this can be done for any type of control you like to bind to a resource, or any other class. I do this for static classes like my application settings as well.
顺便说一下,这很容易实现,可以为您喜欢绑定到资源或任何其他类的任何类型的控件完成。我也对像我的应用程序设置这样的静态类这样做。
Entering code like this:
输入这样的代码:
textBox2.DataBindings.Add("Text", source, "<className>.<PropertyName>");
is not giving me a "good feeling", never mind the spelling
没有给我一种“好感觉”,别介意拼写
Here is a litle sample of the above label that provides a dropdown on the resources of a application.
这是上述标签的一个小示例,它提供了应用程序资源的下拉列表。
First the control, contains 1 new property named ResourceNamethe magic comes from the editor, this one is specified in the annotation above the property and is called ResourceDropDownListPropertyEditor
首先是控件,包含 1 个名为ResourceName的新属性,这个魔法来自编辑器,这个属性在属性上方的注释中指定,名为ResourceDropDownListPropertyEditor
[Editor(typeof(ResourceDropDownListPropertyEditor), typeof(System.Drawing.Design.UITypeEditor))]
The code for the label class:
标签类的代码:
/// <summary>
/// Label bound to resource
/// </summary>
/// <remarks>
/// The bitmap does not appear in the Toolbox for autogenerated controls and components.
/// https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-provide-a-toolbox-bitmap-for-a-control</remarks>
/// <seealso cref="System.Windows.Forms.Label" />
[ToolboxBitmap(typeof(Label))]
public partial class ResourceLabel : Label
{
/// <summary>
/// backing field for the resource key property
/// </summary>
private string mResourceName;
[Browsable(true)]
[DefaultValue("")]
[SettingsBindable(true)]
[Editor(typeof(ResourceDropDownListPropertyEditor), typeof(System.Drawing.Design.UITypeEditor))]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Description("Select the resource key that you would like to bind the text to.")]
public string ResourceName
{
get { return mResourceName; }
set
{
mResourceName = value;
if (!string.IsNullOrEmpty(mResourceName))
{
base.Text = Properties.Resources.ResourceManager.GetString(mResourceName);
}
}
}
/// <summary>
/// Designer helper method: https://msdn.microsoft.com/en-us/library/ms973818.aspx
/// </summary>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
private bool ShouldSerializeResourceName()
{
return !string.IsNullOrEmpty(ResourceName);
}
/// <summary>
/// Will be default text if no resource is available
/// </summary>
[Description("default text if no resource is assigned or key is available in the runtime language")]
public override string Text
{
get { return base.Text; }
set
{
// Set is done by resource name.
}
}
}
Here is the class used for the drop down:
这是用于下拉菜单的类:
/// <summary>
/// used for editor definition on those properties that should be able
/// to select a resource
/// </summary>
/// <seealso cref="System.Drawing.Design.UITypeEditor" />
class ResourceDropDownListPropertyEditor : UITypeEditor
{
IWindowsFormsEditorService _service;
/// <summary>
/// Gets the editing style of the <see cref="EditValue"/> method.
/// </summary>
/// <param name="context">An ITypeDescriptorContext that can be used to gain additional context information.</param>
/// <returns>Returns the DropDown style, since this editor uses a drop down list.</returns>
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
// We're using a drop down style UITypeEditor.
return UITypeEditorEditStyle.DropDown;
}
/// <summary>
/// Displays a list of available values for the specified component than sets the value.
/// </summary>
/// <param name="context">An ITypeDescriptorContext that can be used to gain additional context information.</param>
/// <param name="provider">A service provider object through which editing services may be obtained.</param>
/// <param name="value">An instance of the value being edited.</param>
/// <returns>The new value of the object. If the value of the object hasn't changed, this method should return the same object it was passed.</returns>
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
if (provider != null)
{
// This service is in charge of popping our ListBox.
_service = ((IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)));
if (_service != null)
{
var items = typeof(Properties.Resources).GetProperties()
.Where(p => p.PropertyType == typeof(string))
.Select(s => s.Name)
.OrderBy(o => o);
var list = new ListBox();
list.Click += ListBox_Click;
foreach (string item in items)
{
list.Items.Add(item);
}
if (value != null)
{
list.SelectedValue = value;
}
// Drop the list control.
_service.DropDownControl(list);
if (list.SelectedItem != null && list.SelectedIndices.Count == 1)
{
list.SelectedItem = list.SelectedItem.ToString();
value = list.SelectedItem.ToString();
}
list.Click -= ListBox_Click;
}
}
return value;
}
private void ListBox_Click(object sender, System.EventArgs e)
{
if (_service != null)
_service.CloseDropDown();
}
}
In the end what you get will look like this at design-time:
The resource names are created when you drop the control on your form, changes are not seen till you re-compile and close/open the form or drop a new label on the form.
当您在表单上放置控件时会创建资源名称,直到您重新编译并关闭/打开表单或在表单上放置新标签时才会看到更改。
回答by Luke T O'Brien
I have just been looking at this very thing.
If you own the control, ie it is your own custom control, you can use CodeDOM
我一直在看这个东西。
如果您拥有控件,即它是您自己的自定义控件,则可以使用CodeDOM
Read this articlefor some background and download this exampleto see how it's done.
In our app we need to replace placeholders with "DisplayText" form the database.
So we have Text properties like "Order {Product}"
and we want to replace with GetDisplayText("Order {Product}
")`.
在我们的应用程序中,我们需要用数据库中的“DisplayText”替换占位符。
所以我们有 Text 属性"Order {Product}"
,我们想用GetDisplayText("Order {Product}
“)`替换。
So in order to do this I have added the following code:
因此,为了做到这一点,我添加了以下代码:
statements.OfType<CodeAssignStatement>()
.Where(s => s.Left is CodePropertyReferenceExpression && ((CodePropertyReferenceExpression)s.Left).PropertyName == "Text")
.ToList().ForEach(s =>
{
s.Right = new CodeMethodInvokeExpression(
new CodeMethodReferenceExpression(new CodeTypeReferenceExpression("Core.DisplayText"), "GetDisplayText"),
s.Right);
});
However I am still experimenting with it and I haven't created a working solution yet... But it may help you.
但是我仍在试验它,我还没有创建一个有效的解决方案......但它可能对你有帮助。
:-)
:-)