大家好,现在接手了一个项目,要求多语言。以前没有做过,特来向大家请教:
要求:语言不能用VS的资源文件,读取INI或XML语言文件来实现。我的程序是MDI,在父窗体上我用了一个MENU,可以让用户选择语言种类。另作了一个多语言的类,读取INI或XML。
现在的问题是,我能实现将主窗体的语言实时的改掉(http://topic.csdn.net/u/20100914/21/c092e4bc-d33c-4cef-aa11-31586ac9573b.html),可所有的子窗体,我不知道该如何做。请大家指教。
刚起步,谢谢大家了。
foreach (Form form in Application.OpenForms)
{
//这里是你所有打开的窗体
}
遍历内部控件和子窗体,你递归的遍历,应该没问题把。
public void LoopChangeChild(Control c)
{
//处理c
foreach (Control child in c.Controls)
{
LoopChangeChild(c);
}
}
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;namespace TIM.MultiLanguage
{
public class MultiLanguage
{
private int multi_languageType;
public int Multi_languageType
{
get
{
return multi_languageType;
}
set
{
multi_languageType = value;
}
} private string psth = Environment.CurrentDirectory;
private IniOperate ini = new IniOperate(Environment.CurrentDirectory + @"\Language\en_US.ini"); /// <summary>
/// Language Type:1=English; 2=Chinese; default=English
/// </summary>
public void LanguageChange(TIM.frmMain fMain, int languageType)
{
multi_languageType = languageType;
switch (languageType)
{
case 1:
ini.Path = psth + @"\Language\en_US.ini";
break;
case 2:
ini.Path = psth + @"\Language\zh_CN.ini";
break;
default:
break;
} fMain.Text = ini.IniReadValue("MAIN", "form");
fMain.mainMenu.Items[0].Text = ini.IniReadValue("MAIN_MENU", "menu0_0");
fMain.menuItemFile.DropDownItems[0].Text = ini.IniReadValue("MAIN_MENU", "menu0_1");
fMain.menuItemFile.DropDownItems[1].Text = ini.IniReadValue("MAIN_MENU", "menu0_2");
fMain.menuItemFile.DropDownItems[2].Text = ini.IniReadValue("MAIN_MENU", "menu0_3");
fMain.mainMenu.Items[1].Text = ini.IniReadValue("MAIN_MENU", "menu1_0");
fMain.menuItemView.DropDownItems[0].Text = ini.IniReadValue("MAIN_MENU", "menu1_1");
fMain.menuItemView.DropDownItems[1].Text = ini.IniReadValue("MAIN_MENU", "menu1_2");
fMain.menuItemView.DropDownItems[2].Text = ini.IniReadValue("MAIN_MENU", "menu1_3");
fMain.menuItemView.DropDownItems[3].Text = ini.IniReadValue("MAIN_MENU", "menu1_4");
fMain.menuItemView.DropDownItems[4].Text = ini.IniReadValue("MAIN_MENU", "menu1_5");
}
}
}
TIM.MultiLanguage.LanguageChange(this,1);我的意思是主窗体可以通过this传递过去,那其他子窗体呢?
//这里是你所有打开的窗体
这一行换成
TIM.MultiLanguage.LanguageChange(form,1);//处理c
这一行换成
TIM.MultiLanguage.LanguageChange(c,1);
{
foreach (Form form in Application.OpenForms)
{
TIM.MultiLanguage.LanguageChange(form,1);
}
LoopChangeChild(this);
}public void LoopChangeChild(Control c)
{
TIM.MultiLanguage.LanguageChange(c,1);
foreach (Control child in c.Controls)
{
LoopChangeChild(c);
}
}
我的类public void LanguageChange(TIM.frmMain fMain, int languageType)的这个方法是不是要改
如果不改的话,那我要把所有子窗体的控件全都Public,这样是不是不对的啊?
这个方法写的不好。应该考虑用反射写一个通用任何控件的方法。加上我给你的,才能实现复杂的界面,否则,这个方案有点不可行,如你所说,每个窗体要实现一次。
主要是用INI或XML可供用户编辑就行。
并在预设的虚方法中抛出异常,强制继承者必须覆盖该方法.
//这个是基类窗体,所有窗体都继承它而来,包括主窗体
public partial class FrmBase : Form
{
public FrmBase()
{
InitializeComponent();
}//这个是虚函数,可以子类窗体重新实现,也可以在基类遍历所有控件修改语言
//但建议在子类实现
public virtual void LanguageChange(int languageType)
{
switch (languageType)
{
case 0:
Text = "中文";
break; case 1:
Text = "英文";
break;
}
}//这里使用HWND_BROADCAST广播消息的方法,通知所有窗体改变语言
//100 101 102 103都是自定义参数,可修改
protected override void WndProc(ref Message m)
{
if (m.Msg == 100 && m.WParam.ToInt32() == 101)
{
if (m.LParam.ToInt32() == 102)
LanguageChange(0);
else if(m.LParam.ToInt32() == 103)
LanguageChange(1);
}
else
base.WndProc(ref m);
}
}//主窗体的代码:
//主窗体共有四个测试按钮 private const int HWND_BROADCAST = 0xFFFF;
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam); private void button1_Click(object sender, EventArgs e)
{
//广播消息,修改为中文
SendMessage(HWND_BROADCAST, 100, 101, 102);
} private void button2_Click(object sender, EventArgs e)
{
//广播消息,修改为英文
SendMessage(HWND_BROADCAST, 100, 101, 103);
} private void button3_Click(object sender, EventArgs e)
{
//打开继承于FrmBase的窗体
FrmBase frm = new FrmBase();
frm.Show();
} private void button4_Click(object sender, EventArgs e)
{
//Form1也继承于FrmBase
Form1 frm = new Form1();
frm.Show();
}
这方法可以,我没想到...
其实楼主的问题还可以使用更加优雅的方法实现:观察者模式
慢慢的想放弃INI和XML,改用资源文件了。
这个纠结啊.......
[窗体的名称]
控件名称_0=中文
控件名称_1=英文各个窗体接到改变语言的消息后,使用窗体名称和控件名称就能直接读出中英文的数据了
难道我要在父窗体里把所有的子窗体再都实例化一次,然后各执行一次每个子窗体的的refresh()事件?子窗体好多的。
只是文字,其他的不考虑,没有什么listview 之类的控件,就是一些label,txtbox,button
模仿观察者模式写成的下载
http://blog.csdn.net/wuyazhe/archive/2010/09/20/5895754.aspx
ps
ZengHD,广播消息的话,就可能不止当前进程或线程的,其他副本也跟着修改了。
各有利弊。楼主自己搭配使用把。
有了解过多语言的实现方法。bitcomet0.99版本。
ini
xml
string常量化
都很直观。