大家好,现在接手了一个项目,要求多语言。以前没有做过,特来向大家请教:
要求:语言不能用VS的资源文件,读取INI或XML语言文件来实现。我的程序是MDI,在父窗体上我用了一个MENU,可以让用户选择语言种类。另作了一个多语言的类,读取INI或XML。
现在的问题是,我能实现将主窗体的语言实时的改掉(http://topic.csdn.net/u/20100914/21/c092e4bc-d33c-4cef-aa11-31586ac9573b.html),可所有的子窗体,我不知道该如何做。请大家指教。
刚起步,谢谢大家了。

解决方案 »

  1.   

    遍历一下就可以了。
    foreach (Form form in Application.OpenForms)
    {
        //这里是你所有打开的窗体
    }
    遍历内部控件和子窗体,你递归的遍历,应该没问题把。
    public void LoopChangeChild(Control c)
    {
        //处理c
        foreach (Control child in c.Controls)
        {
            LoopChangeChild(c);
        }
    }
      

  2.   

    我的多语言类代码如下,应该怎么修改?小弟刚起步,不胜感激using System;
    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");
            }
        }
    }
      

  3.   

    然后再父窗体里的menu下执行上面这个类的
    TIM.MultiLanguage.LanguageChange(this,1);我的意思是主窗体可以通过this传递过去,那其他子窗体呢?
      

  4.   

    已经给你写那么详细的了
    //这里是你所有打开的窗体
    这一行换成
    TIM.MultiLanguage.LanguageChange(form,1);//处理c
    这一行换成
    TIM.MultiLanguage.LanguageChange(c,1);
      

  5.   

    private void button1_Click(object sender, EventArgs e)
    {
        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);
        }
    }
      

  6.   

    回楼上的,我还是有点不明白这个原理
    我的类public void LanguageChange(TIM.frmMain fMain, int languageType)的这个方法是不是要改
    如果不改的话,那我要把所有子窗体的控件全都Public,这样是不是不对的啊?
      

  7.   

    public void LanguageChange
    这个方法写的不好。应该考虑用反射写一个通用任何控件的方法。加上我给你的,才能实现复杂的界面,否则,这个方案有点不可行,如你所说,每个窗体要实现一次。
      

  8.   

    如果我的方法不可行,那还有其他好的方法吗?
    主要是用INI或XML可供用户编辑就行。
      

  9.   

    如果不用资源文件的话,你要走一个非常痛苦的过程就像当年,我曾想过在C#中实现DOC/VIEW一样可以试试所有的string常量伪常数化(由一个类的属性来实现,类实现一个Reset方法,更新语言,并读取相应的ini或xml和并触发一个Change事件,所有的窗口在收到该类的Change事件后,自动更新UI的显式文本)
      

  10.   

    除了我说的这个类,所有的地方,都要避免使用string常数,即,除了这个类外,任何地方都不要出现英文的双引号
      

  11.   

    我感觉很简单啊,写个基类,里面有个LanguageChange,然后~~~~~~~
      

  12.   

    对于常使用设计器的人来说,必须大但的用#if DEGUG把设计器中窗口的构造函数所调用的InitializeComponent方法,并在最终编译时,定义到一个自己定义的InitializeComponent方法中,在你这个自定义的InitializeComponent方法中,对任何控件的初始化,都不需要使用string常量,而是使用那个类中的属性.
      

  13.   

    是的,需要这样的一个基类.在构造时,用一个虚方法去预定一个静态的LanguageChange事件
    并在预设的虚方法中抛出异常,强制继承者必须覆盖该方法.
      

  14.   

        
    //这个是基类窗体,所有窗体都继承它而来,包括主窗体
    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();
            }
      

  15.   

    SendMessage(HWND_BROADCAST........
    这方法可以,我没想到...
      

  16.   

    上面使用HWND_BROADCAST是流氓手段
    其实楼主的问题还可以使用更加优雅的方法实现:观察者模式
      

  17.   

    和我的想法基本一致,你的方法也类似于事件处理,只不过我把string常量给归了一下类,相当于动态给软件做一个内部的汉化包.如果.Net最终生成的可执行文件,也会给常量做一个归类的话,应该还有更简便的方法
      

  18.   

    看的这么多,头都大了,现在也不知道该怎么用了。
    慢慢的想放弃INI和XML,改用资源文件了。
    这个纠结啊.......
      

  19.   

    INI也可以很好的处理啊,INI文件结构可以这样,
    [窗体的名称]
    控件名称_0=中文
    控件名称_1=英文各个窗体接到改变语言的消息后,使用窗体名称和控件名称就能直接读出中英文的数据了
      

  20.   

    我就是想知道,怎么在我自定义的多语言类里,实现让各个子窗体接收到改变语言的消息?我在多语言类里,把INI的KEY和value都读出来了。
    难道我要在父窗体里把所有的子窗体再都实例化一次,然后各执行一次每个子窗体的的refresh()事件?子窗体好多的。
      

  21.   

    其实只有文本还不够,比如ListView ,你就不能只取Text属性,当然要序列化Column的显示文本,还有每个ListViewItem的每一项,语言切换了,也不只是更新控件,比如datagridview,listview的内容你如何动态的写个方法也一起改变呢?
      

  22.   

    我是说datagridview的列头,listview的列头
      

  23.   


    只是文字,其他的不考虑,没有什么listview 之类的控件,就是一些label,txtbox,button
      

  24.   

    不好意思啊,我23楼的HWND_BROADCAST消息,只对顶层窗口有效,对子窗口无效,所以不能用于MDI窗口,那只能使用更加优雅的方法实现了开着《大话设计模式》
    模仿观察者模式写成的下载
      

  25.   

    自己实现的一个对窗体的资源化方法。 
    http://blog.csdn.net/wuyazhe/archive/2010/09/20/5895754.aspx
      

  26.   

    囧,刚贴错2次上传的项目。刚更新好了。
    ps
    ZengHD,广播消息的话,就可能不止当前进程或线程的,其他副本也跟着修改了。
    各有利弊。楼主自己搭配使用把。
      

  27.   

    非常感谢各位的帮助,特别是ZengHD和wuyazhe,最终我采用的是ZengHD的观察者模式方法。可能是我比较笨,他的这个方法我能看懂的。我都不好意思再问wuyazhe了,真的,非常谢谢你。
      

  28.   

    。。
    有了解过多语言的实现方法。bitcomet0.99版本。
    ini
    xml
    string常量化
    都很直观。