C#区域性语言(CultureInfo)与资源本地化(WINFORM,多线程,原理可适用于网络开发)

有时候我们会按照特定需要来修改系统的显示语言(资源),本文即简要地描述了修改当前线程的区域性并使用本地化资源展现。

首先对需要使用不同区域性设置的用户界面设置不同的语言资源:

选择窗体,在属性栏中修改其Language属性,此时用户界面的Localizable属性也已经被调整为true;

然后编辑该区域性语言的本地化资源,即各个控件的可本地化的所有属性都可以,并保存;

        private void btnApply_Click(object sender,EventArgs e)
        {
            if(cmbLanguage.SelectedIndex < 0)
            {
                return;
            }
            string sCultureName = cmbLanguage.SelectedItem.ToString();

            // 更改当前线程的 CultureInfo
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(sCultureName);

            //对当前窗体应用更改后的资源
            ApplyResource();
        }

然后增加一个修改区域性的功能:

其实质就是设置当期线程的当前区域性,即Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(sCultureName);

但是我们会发现这样一个缺陷:通常我们会使用到多线程处理多个事务,于是修改当前线程的当前区域性对其他线程无效,即使是主线程的区域性被设置,子线程依然不会应用其区域性设置,于是需要给每个新建的子线程设置区域性。

而将其设置为主线程的区域性即可解决这样一个问题:t.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;

        private void btnFromLanguage_Click(object sender,EventArgs e)
        {
            Thread t = new Thread(new ThreadStart(StartForm2));

            // 使用多线程时,由于各个线程的区域性不一样,所以要引用当前主线程的区域性
            t.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;

            t.Start();
        }

        private void StartForm2()
        {
            new TestForm().ShowDialog();
        }

设置线程的区域性之后只会给未启动的线程(Start之前)在启动之后,使用区域性资源初始化用户界面,而对于已经初始化的用户界面,则要读取本地化资源刷新当前设置,这里使用到资源管理器,并用其提供的ApplyResources方法来给指定的对象(其value参数)赋予给定资源名称(其objectName参数)对应的资源内容,为了应用于其包含的所有子控件,还应遍历其包含的所有子控件并同样对其使用ApplyResources方法:

        /// <summary>
        /// 应用资源
        /// </summary>
        private void ApplyResource()
        {
            ComponentResourceManager res = new ComponentResourceManager(typeof(Jokes.Language.LanguageTest));

            foreach(Control ctl in Controls)
            {
                ApplyResource(ctl,res);
            }
            res.ApplyResources(this,"$this");
        }

        /// <summary>
        /// 使用由指定资源管理器管理的资源给控件及其子控件绑定资源
        /// </summary>
        /// <param name="control">
        /// 将绑定资源的控件(及其子控件)
        /// </param>
        /// <param name="resourceManager">
        /// 管理资源的资源管理器对象
        /// </param>
        private void ApplyResource(Control control,ComponentResourceManager resourceManager)
        {
            if(null == control || null == resourceManager)
            {
                return;
            }
            foreach(Control ctl in control.Controls)
            {
                if(ctl.Controls != null && ctl.Controls.Count > 0)
                {
                    // 递归的效率通常在递归层次超过5-6层时明显较低,不建议使用
                    ApplyResource(ctl,resourceManager);
                }
                resourceManager.ApplyResources(ctl,ctl.Name);
            }
            resourceManager.ApplyResources(control,control.Name);
        }

到此基本上就已经实现了,但是还有一些特殊的,比如已经打开的多文档窗体或多个非模式化窗体,这种情况下,那还得再对每一个子窗体或相关对象也重新刷新一次其区域性资源,否则只能关闭之,并再次启动。如果是用其他线程创建的对象,还要考虑线程间访问等问题,故比较折中的方法是在线程启动之前设置其区域性。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值