[连载]《C#通讯(串口和网络)框架的设计与实现》- 13.中英文版本切换设计
目 录
第十三章 中英文版本切换设计... 2
13.1 不用自带的资源文件的理由... 2
13.2 配置文件... 2
13.3 语言管理类... 3
13.4 应用管理类... 12
13.5 小结... 12
第十三章 中英文版本切换设计
13.1 不用自带的资源文件的理由
可以利用resx资源文件进行多语言设计,resx文件本身是kv类型的资源文件,设计好资源文件后,启动软件时可以通过CurrentCulture属性设置要显示的语言。实现代码如下:
//设置成英文版本
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-us");
但是,软件涉及到多线程、线程池、异步等应用的时候,当前线程设置了英文版本,其他线程还是默认的语言文化,例如:主线程设置了en-US,但是新建线程和其他已经存在的线程还是zh-CN,如果各部分UI不在同一线程更新的话,语言文化的设置是不一样的,所以没有办法实现统一的语言显示。
那么,可不可以通过进程获得所有线程信息,统一进行设置语言文化信息呢,的确是一个很好的想法。但是,通过实践证明这是行不能的,可能造反软件异常退出。为什么会出现这个现象呢?我猜想,一个进程中不仅包括自定义的线程,还存在系统级的线程,这样操作是一件危险的事。
难道就没有办法实现了吗?人不可能被尿憋死。在.NET 4.5中就简单多了,直接使用System.Globalization命名空间内CultureInfo类型的 DefaultThreadCurrentCulture和DefaultThreadCurrentUICulture属性。设置好后,每一个新线程的 CurrentUICulture和CurrentCulture属性都会和这个值保持一致的。CultureInfo类具体怎么实现的,还没有研究过。
为了兼容XP操作系统,还在使用.NET4.0的框架。相信也可以实现CultureInfo类的功能,但是不如自己设计一套语言版本方案更直接、更省时间。有时间的情况下可以研究一下CultureInfo类的实现。
13.2 配置文件
先设计语言配置文件,文件格式采用XML,存储方式采用KV的方式,文件命名可以自定义,例如:cn.xml、en.xml。如下图:

Key的定义有两种方式,第一种:窗体命名.控件命名,可以对窗体的控件统一改变显示的语言信息。第二种:直接定义关键字,可以对提示信息、状态信息等单独词条改变显示的语言信息。Value就是最终要显示语言的具体内容,完全自定义。
13.3 语言管理类
- 定义一个词条对应的可序列化的类。代码如下:
[Serializable]
public class CultureItem
{
/// <summary>
/// 控件的级联ID,中间用"."分隔
/// </summary>
[XmlAttribute]
public string Key { set; get; } /// <summary>
/// 中文或英文描述
/// </summary>
[XmlAttribute]
public string Value { set; get; }
}
- 定义一个设置语言属性的枚举。代码如下:
public enum CultureLanguage
{
[EnumDescription("中文")]
Chinese,
[EnumDescription("英文")]
English
}
- 开发一个语言管理类库,本质上是根据语言配置文件对Dictionary<string, string>字典缓存进行操作。实现代码如下:
public class CultureMananger
{
private static Dictionary<string, string> _dic = new Dictionary<string, string>();
private static string _cnPath = Application.StartupPath + "\\SuperIO\\Language\\cn.xml";
private static string _enPath = Application.StartupPath + "\\SuperIO\\Language\\en.xml";
private static object SyncObject = new object(); /// <summary>
/// 加载语言文件到缓存中
/// </summary>
public static void LoadCulture()
{
lock (SyncObject)
{
if (IsLanguage)
{
try
{
_dic.Clear();
string path = String.Empty;
if (Language == CultureLanguage.Chinese)
{
path = _cnPath;
}
else if (Language == CultureLanguage.English)
{
path = _enPath;
}
if (File.Exists(path))
{
List<CultureItem> itemList =SerializeOperation.SerializeOperation.GetSerialize<List<CultureItem>>(path);
foreach (CultureItem item in itemList)
{
_dic.Add(item.Key, item.Value);
}
}
}
catch (Exception ex)
{
GeneralLog.WriteLog(ex);
}
}
}
} /// <summary>
/// 清除缓存中的语言信息
/// </summary>
public static void ClearCache()
{
lock (SyncObject)
{
_dic.Clear();
}
} /// <summary>
/// 设置和获得语言类型属性
/// </summary>
public static CultureLanguage Language
{
set
{
if (GlobalProperty.GetInstance().Language != value)
{
GlobalProperty.GetInstance().Language = value;
GlobalProperty.GetInstance().Save();
LoadCulture();
}
}
get { return GlobalProperty.GetInstance().Language; }
} /// <summary>
/// 获得词条对应的描述信息
/// </summary>
/// <param name="formName">窗体名称</param>
/// <param name="field">词条字段</param>
/// <returns>对应的描述信息</returns>
public static string GetString(string formName, string field)
{
return GetString(String.Format("{0}.{1}", formName, field));
} /// <summary>
/// 获得词条对应的描述信息
/// </summary>
/// <param name="key">字段的关键字</param>
/// <returns></returns>
public static string GetString(string key)
{
lock (SyncObject)
{
if (IsLanguage)
{
string val = String.Empty;
if (_dic.ContainsKey(key))
{
_dic.TryGetValue(key, out val);
}
return val;
}
else
{
return String.Empty;
}
}
} /// <summary>
/// 应用窗体,改变语言显示
/// </summary>
/// <param name="frm"></param>
public static void ApplyResourcesForm(Form frm)
{
if (IsLanguage)
{
string frmText = GetString(frm.Name);
if (!String.IsNullOrEmpty(frmText))
{
frm.Text = frmText;
}
ApplyControls(frm.Name, frm.Controls);
}
} /// <summary>
/// 应用BarManager工具具,改变语言显示
/// </summary>
/// <param name="name"></param>
/// <param name="bar"></param>
public static void AppResourceBarItem(string name, BarManager bar)
{
if (IsLanguage)
{
string key = String.Empty;
foreach (BarItem item in bar.Items)
{
key = String.Format("{0}.{1}", name, item.Name);
string val = GetString(key);
if (!String.IsNullOrEmpty(val))
{
item.Caption = val;
}
}
}
} /// <summary>
/// 应用控件,改变语言显示
/// /summary>
/// <param name="name"></param>
/// <param name="ctrls"></param>
public static void ApplyControls(string name, Control.ControlCollection ctrls)
{
if (IsLanguage)
{
foreach (Control ctrl in ctrls)
{
if (ctrl is MenuStrip) //MenuStrip StatusStrip
{
ApplyMenuStrip(name, (MenuStrip) ctrl);
}
else if (ctrl is StatusStrip)
{
ApplyStatusStrip(name, (StatusStrip) ctrl);
}
else if (ctrl is ListView)
{
ApplyListView(name, (ListView) ctrl);
}
else
{
ApplyControls(name, ctrl);
} if (ctrl.HasChildren)
{
ApplyControls(name, ctrl.Controls);
}
}
}
} internal static bool IsLanguage
{
get
{
if (File.Exists(_cnPath) && File.Exists(_enPath))
{
return true;
}
else
{
return false;
}
}
} private static void ApplyControls(string name, Control ctrl)
{
string key = String.Format("{0}.{1}", name, ctrl.Name);
string text = GetString(key);
if (!String.IsNullOrEmpty(text))
{
ctrl.Text = text;
}
} private static void ApplyMenuStrip(string name, MenuStrip menu)
{
foreach (ToolStripMenuItem item in menu.Items)
{
ApplyMenuItem(name, item);
}
} private static void ApplyMenuItem(string name, ToolStripMenuItem item)
{
string key = String.Format("{0}.{1}", name, item.Name);
string text = GetString(key);
if (!String.IsNullOrEmpty(text))
{
item.Text = text;
}
if (item.DropDownItems.Count > 0)
{
foreach (ToolStripMenuItem subItem in item.DropDownItems)
{
ApplyMenuItem(name, subItem);
}
}
} private static void ApplyStatusStrip(string name, StatusStrip status)
{
string key = String.Empty;
foreach (ToolStripItem item in status.Items)
{
key = String.Format("{0}.{1}", name, item.Name);
string val= GetString(key);
if (!String.IsNullOrEmpty(val))
{
item.Text = val;
}
}
} private static void ApplyListView(string name, ListView lv)
{
string key = String.Empty;
foreach (ColumnHeader header in lv.Columns)
{
key = String.Format("{0}.{1}", name, header.Tag == null ? "" : header.Tag.ToString());
string val = GetString(key);
if (!String.IsNullOrEmpty(val))
{
header.Text = val;
}
}
}
}
13.4 应用管理类
在软件启动时可以使用CultureMananger管理类,具体应用代码如下:
CultureMananger.LoadCulture();
CultureMananger.ApplyControls("MainForm",this.Controls);
string state=CultureMananger.GetString("State.Normal");
13.5 小结
这是一个小的工具组件,具有一定的通用性。
作者:唯笑志在
Email:504547114@qq.com
QQ:504547114
.NET开发技术联盟:54256083
文档下载:http://pan.baidu.com/s/1pJ7lZWf
官方网址:http://www.bmpj.net
[连载]《C#通讯(串口和网络)框架的设计与实现》- 13.中英文版本切换设计的更多相关文章
- [连载]《C#通讯(串口和网络)框架的设计与实现》- 0.前言
目 录 前言 前言 刚参加工作,使用过VB.VC开发软件,随着C#的崛起,听说是C++++,公司决定以后开发软件使用C#,凭借在 ...
- 《连载 | 物联网框架ServerSuperIO教程》-4.如开发一套设备驱动,同时支持串口和网络通讯。附:将来支持Windows 10 IOT
1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架Serve ...
- [连载]《C#通讯(串口和网络)框架的设计与实现》-1.通讯框架介绍
[连载]<C#通讯(串口和网络)框架的设计与实现>- 0.前言 目 录 第一章 通讯框架介绍... 2 1.1 通讯的本质... 2 1 ...
- [连载]《C#通讯(串口和网络)框架的设计与实现》- 6.通讯控制器的设计
目 录 第六章 通讯控制器的设计... 2 6.1 控制器接口... 2 6.2 串口控制器... 3 6.3 ...
- [连载]《C#通讯(串口和网络)框架的设计与实现》-2.框架的总体设计
目 录 C#通讯(串口和网络)框架的设计与实现... 1 (SuperIO)- 框架的总体设计... 1 第二章 框架总体的设计... 2 2.1 ...
- [连载]《C#通讯(串口和网络)框架的设计与实现》- 5.串口和网络统一IO设计
目 录 第五章 串口和网络统一IO设计... 2 5.1 统一IO接口... 2 5.1.1 串口IO.. 4 5.1.2 网络IO.. ...
- [连载]《C#通讯(串口和网络)框架的设计与实现》-4.设备驱动管理器的设计
目 录 第四章 设备驱动管理器的设计... 2 4.1 接口定义... 2 4.2 设备容器... 7 4.3 ...
- [连载]《C#通讯(串口和网络)框架的设计与实现》-3.设备驱动的设计
目 录 第三章 设备驱动的设计... 2 3.1 初始化设备... 4 3.2 运行设备接口设计... 4 3.3 ...
- [连载]《C#通讯(串口和网络)框架的设计与实现》- 7.外部接口的设计
目 录 第七章 外部接口的设计... 2 7.1 插件接口... 2 7.2 图形显示接口... 3 7.3 ...
随机推荐
- 学习C的笔记
[unsigned] 16位系统中一个int能存储的数据的范围为-32768~32767,而unsigned能存储的数据范围则是0~65535.由于在计算机中,整数是以补码形式存放的.根据最高位的不同 ...
- Java实现多线程断点下载(下载过程中可以暂停)
线程可以理解为下载的通道,一个线程就是一个文件的下载通道,多线程也就是同时开启好几个下载通道.当服务器提供下载服务时,使用下载者是共享带宽的,在优先级相同的情况下,总服务器会对总下载线程进行平均分配. ...
- SQL Server 2014聚集列存储索引
转发请注明引用和原文博客(http://www.cnblogs.com/wenBlog) 简介 之前已经写过两篇介绍列存储索引的文章,但是只有非聚集列存储索引,今天再来简单介绍一下聚集的列存储索引,也 ...
- 让MacBook识别noppoo mini 84
让MacBook识别noppoo mini 84 noppoo默认是没有mac驱动的,需要下载一个IOUSBHIDDriverDescriptorOverride否则无法noppoo的键位是识别错误的 ...
- 在 Linux 中使用 Git 及其 和 Eclipse 的集成
##参考资料## 我是通过阅读<Pro Git>这本书学习 Git 的,我读的时候还是第一版的英文版,现在已经出第二版了,而且英文版和中文版都有.英文第二版的地址是 [https://gi ...
- 站在风口,你或许就是那年薪20w+的程序猿
最近面试了一些人,也在群上跟一些群友聊起,发现现在的互联网真是热,一些工作才两三年的期望的薪资都是十几K的起,这真是让我们这些早几年就成为程序猿的情何以堪!正所谓是站在风口上,猪也能飞起来!我在这里就 ...
- python装饰器
今天看了装饰器的一些内容,感觉@修饰符还是挺抽象的. 装饰器就是在不用改变函数实现的情况下,附加的实现一些功能,比如打印日志信息等.需要主意的是装饰器本质是一个高阶函数,她可以返回一个函数. 装饰器需 ...
- Linux进程管理及while循环
目录 进程的相关概念 进程查看及管理工具的使用 Linux系统作业控制 调整进程优先级 网络客户端工具 bash之while循环 20.1.进程类型 守护进程 daemon,在系统引导过程中启动的进程 ...
- angular2
1 class两种写法 (1).直接写 class="{{}}"; (2).数组 arr[a,b,c] ng-class = "arr" 2.class和sty ...
- 【Win 10 应用开发】UDP广播
我们知道,对于UDP协议的通信,除了可以用来聊天外,可以发送广播数据.只要向广播地址的某个端口发送数据就可以进行广播,子网中只要监听该端口的socket就能收到广播消息. 最简单的方法就是向255.2 ...