在运行时更改Form语言的正确方法是什么?
InitializeComponent();
关于这个问题有很多半成文,但是没有一个能提供真正的答案来解决这个问题的正确方法吗?
更新
澄清我的问题:
做这样的事情:
public Form1()
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de");
this.InitializeComponent();
}
工作正常,我的所有控件和资源中的其他所有内容都可以正确转换。 并做了类似的事情:
private void button1_Click(object sender, EventArgs e)
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en");
}
什么都不做,Form保持我在InitializeComponent();
答案 0 :(得分:21)
我相信Hans Passant评论中显示的解决方案可能是唯一的(一般)解决方案。
就个人而言,我将这个基类用于所有需要本地化的表单:
public class LocalizedForm : Form
{
/// <summary>
/// Occurs when current UI culture is changed
/// </summary>
[Browsable(true)]
[Description("Occurs when current UI culture is changed")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Category("Property Changed")]
public event EventHandler CultureChanged;
protected CultureInfo culture;
protected ComponentResourceManager resManager;
/// <summary>
/// Current culture of this form
/// </summary>
[Browsable(false)]
[Description("Current culture of this form")]
[EditorBrowsable(EditorBrowsableState.Never)]
public CultureInfo Culture
{
get { return this.culture; }
set
{
if (this.culture != value)
{
this.ApplyResources(this, value);
this.culture = value;
this.OnCultureChanged();
}
}
}
public LocalizedForm()
{
this.resManager = new ComponentResourceManager(this.GetType());
this.culture = CultureInfo.CurrentUICulture;
}
private void ApplyResources(Control parent, CultureInfo culture)
{
this.resManager.ApplyResources(parent, parent.Name, culture);
foreach (Control ctl in parent.Controls)
{
this.ApplyResources(ctl, culture);
}
}
protected void OnCultureChanged()
{
var temp = this.CultureChanged;
if (temp != null)
temp(this, EventArgs.Empty);
}
}
然后我不是直接更改 Thread.CurrentThread.CurrentUICulture ,而是在静态管理器类中使用此属性来更改UI文化:
public static CultureInfo GlobalUICulture
{
get { return Thread.CurrentThread.CurrentUICulture; }
set
{
if (GlobalUICulture.Equals(value) == false)
{
foreach (var form in Application.OpenForms.OfType<LocalizedForm>())
{
form.Culture = value;
}
Thread.CurrentThread.CurrentUICulture = value;
}
}
}
答案 1 :(得分:3)
我找到了另一种方式:
在私有方法中移动初始化表单代码,如下所示
private void FormInitialize() {/*Your code here*/}
在表单构造函数中使用它
public Form1()
{
InitializeComponent();
FormInitialize();
}
从Button,menuItem或其他类似的调用方法
private void ChangeCultureToFrench_Click(object sender, EventArgs e)
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("fr");
this.Controls.Clear();
this.InitializeComponent();
FormInitialize();
}
我希望这会有所帮助; - )
答案 2 :(得分:2)
几分钟前我发现了这种方法。只需快速简单地重新启动主窗体即可。 Meybe它会帮助某人。事件在我自己的表单内创建,当用户从菜单中选择语言但在所选文化的名称保存到设置中后调用。然后从该设置加载文化名称。完全按照我的需要工作,看起来像是正确的解决方案。
static class Program
{
private static bool doNotExit = true;
private static FormMain fm;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
while(doNotExit)
{
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo(Properties.Settings.Default.language);//
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(Properties.Settings.Default.language);//
doNotExit = false;
fm = new FormMain();
fm.lanugageChangedEvent += new EventHandler(main_LanugageChangedEvent);
Application.Run(fm);
}
}
static void main_LanugageChangedEvent(object sender, EventArgs e)
{
doNotExit = true;
fm.Close();
}
}
答案 3 :(得分:0)
在参考ColumnHeader .NET框架错误时,我最近也发现了这个错误并发布了一个关于它的问题(我没有收到任何回复)。我能够通过硬编码ColumnHeaders的更改来解决问题。例如:
resources.ApplyResources(_myHeader, "_myHeader", culture);
你基本上只是用名称的文字字符串替换.Name的调用。我测试了这个并且它有效。不幸的是,这意味着它不适合用作更改所有控件的代码的一部分。您需要为需要更改的每个ColumnHeader对象添加一行。如果您的列表视图具有可变数量的列,那可能会变得棘手。另一种选择是创建本地化资源文件。我假设你可能已经有了消息框文本和其他字符串之类的东西。然后,您可以在资源文件中添加一个条目,如“columnHeader_myHeader”,并为每种语言设置相应的语言文本。最后,您可以使用以下方法手动将文本更改为列标题:
_myHeader.Text = myResourceFileName.columnHeader_myHeader;
这将根据当前的线程文化选择适当的语言。 汉斯是正确的,因为在.NET中执行本地化似乎并不是一种万无一失的“正确”方式,尽管您可以使用各种工具。对于像工作申请这样的东西,即使这个建议可能已经太晚了,我的建议是学习尽可能多的不同方法来进行本地化,学习利弊,然后选择一个系统并且能够争论为什么你认为这是“适当的”选择。他们可能更关心你的逻辑和推理以及先前经验的证明,而不是实际的方法。
答案 4 :(得分:0)
希望这对任何人都有帮助,我发现它最适合我,因为我需要根据lang更改按钮位置(浏览搜索框的右侧或左侧以及文本字段旁边的标签)。
从主窗体调用,无论何时想要initialView(视图类的一部分)并随时更改lang(和更多)(只需连接到正确的xml文件):
public void initialView()
{
//Set rightToLeft values
initialIndent(mainForm);
//set visual text values
initialTxt();
}
private void initialTxt()
{
// Are there any more controls under mainObj (Form1)?
Boolean endOfElemsUnderPnl = false;
// The current Control im working on
Object curObj = mainForm;
do
{
// MenuStrip needs to be handled separately
if (typeof(MenuStrip).ToString().Equals(curObj.GetType().ToString()))
{
foreach (ToolStripMenuItem miBase in ((MenuStrip)(curObj)).Items)
{
miBase.Text = mainForm.dbCon.getData(miBase.Name.ToString());
foreach (ToolStripMenuItem miInnerNode in miBase.DropDownItems)
{
miInnerNode.Text = mainForm.dbCon.getData(miInnerNode.Name.ToString());
}
}
}
// Any other Control i have on the form
else
{
((Control)(curObj)).Text = mainForm.dbCon.getData(((Control)(curObj)).Name.ToString());
}
curObj = mainForm.GetNextControl(((Control)(curObj)), true);
// Are there any more controls under mainObj?
if (null == curObj)
{
endOfElemsUnderPnl = true;
}
} while (!endOfElemsUnderPnl);
}
private void initialIndent(frmMyFileManager parent)
{
if (parent.Language.Equals("Hebrew"))
{
parent.RightToLeft = RightToLeft.Yes;
}
else if (parent.Language.Equals("English"))
{
parent.RightToLeft = RightToLeft.No;
}
else
{
parent.RightToLeft = RightToLeft.No;
}
}
这是一个在运行时对我来说有多容易的例子:
private void selectLanguageToolStripMenuItem_Click(object sender, EventArgs e)
{
DialogResult res = MessageBox.Show(this, "click yes for english and no for hebrew", "Select language", MessageBoxButtons.YesNoCancel);
if (DialogResult.Yes == res)
{
Language = "English";
}
else if (DialogResult.No == res)
{
Language = "Hebrew";
}
dbCon = new CDBConnector("****\\lang" + Language + ".xml");
view.initialView();
}