首先定义一个中英文切换的静态类 然后在类里面写如下代码
cs
/// <summary>
/// 静态语言管理类,用于全局管理应用程序的语言切换、资源加载和事件通知。
/// 通过设置 Language 属性可动态切换中英文等语言,并自动更新界面资源。
/// </summary>
public static class LanguageModel
{
/// <summary>
/// 组件资源管理器,用于访问本地化资源(如字符串、图片等)。
/// 默认加载英文资源(Resources.Resource_en)。
/// </summary>
public static ComponentResourceManager crm = new ComponentResourceManager(typeof(Resources.Resource_en));
/// <summary>
/// 中文切换事件委托。当语言切换为中文时触发订阅的方法。
/// 示例:LanguageModel.ChineseChangeAction += UpdateUIForChinese;
/// </summary>
public static Action ChineseChangeAction { get; set; }
/// <summary>
/// 英文切换事件委托。当语言切换为英文时触发订阅的方法。
/// 示例:LanguageModel.EnglishChangeAction += UpdateUIForEnglish;
/// </summary>
public static Action EnglishChangeAction { get; set; }
/// <summary>
/// 私有字段,存储当前语言代码(默认值为 "zh")。
/// 有效值:"zh"(中文)、"en"(英文)。
/// </summary>
private static string language = "zh";
/// <summary>
/// 当前应用程序语言属性。
/// 获取或设置语言时,会自动切换资源文件和触发对应事件。
/// </summary>
/// <example>
/// 切换到中文:LanguageModel.Language = "zh";
/// 切换到英文:LanguageModel.Language = "en";
/// </example>
public static string Language
{
// 获取当前语言代码
get => language;
// 设置语言并执行切换逻辑
set
{
// 更新当前语言
language = value;
// 根据语言代码执行不同操作
switch (value)
{
case "zh": // 中文
// 触发中文切换事件(如果已订阅)
ChineseChangeAction?.Invoke();
// 加载中文资源文件
crm = new ComponentResourceManager(typeof(Resources.Resource_zh));
break;
case "en": // 英文
// 触发英文切换事件(如果已订阅)
EnglishChangeAction?.Invoke();
// 加载英文资源文件
crm = new ComponentResourceManager(typeof(Resources.Resource_en));
break;
// 可扩展其他语言支持
// default:
// throw new ArgumentException("Unsupported language code.");
}
}
}
}
ComponentResourceManager
是 .NET Framework 中的一个类(位于 System.ComponentModel
命名空间),专门用于管理和访问本地化资源(如多语言文本、图片、图标等)。它在 WinForms 应用程序中尤其常见,用于动态加载不同语言的界面资源。
为什么用 typeof(Resources.Resource_xx)
?
-
通过
typeof
指定资源文件的强类型类,确保编译器检查资源是否存在。 -
资源文件会被编译成嵌入资源(Embedded Resource),运行时直接从程序集中加载。
如何使用
cs
/// <summary>
/// 切换应用程序界面语言为中文,并更新所有已打开的窗体资源
/// </summary>
private void ChineseChange()
{
// 1. 设置当前线程的区域性(Culture)为中文
// CurrentCulture 影响数字、日期等格式
Thread.CurrentThread.CurrentCulture = new CultureInfo("zh");
// 2. 设置当前线程的UI区域性(UICulture)为中文
// CurrentUICulture 影响资源文件加载(如界面文字)
Thread.CurrentThread.CurrentUICulture = new CultureInfo("zh");
// 3. 遍历应用程序中所有已打开的窗体
foreach (Form f in Application.OpenForms)
{
// 4. 对每个窗体应用新的资源设置
// 这会根据当前UICulture重新加载对应语言的资源
ApplyResource(f);
}
}
-
区域性设置:
-
CurrentCulture
:影响数字、日期、货币等区域性相关格式 -
CurrentUICulture
:专门控制界面元素的本地化资源加载
-
cs
/// <summary>
/// 根据当前线程的区域性设置,为指定控件应用对应的语言资源
/// </summary>
/// <param name="control">要应用资源的目标控件</param>
public void ApplyResource(Control control)
{
// 1. 根据当前线程的区域性设置选择合适的资源文件
switch (Thread.CurrentThread.CurrentCulture.Name)
{
case "en": // 英文环境
// 初始化英文资源管理器,加载英文资源文件
crm = new ComponentResourceManager(typeof(Resources.Resource_en));
break;
case "zh": // 中文环境
// 初始化中文资源管理器,加载中文资源文件
crm = new ComponentResourceManager(typeof(Resources.Resource_zh));
break;
default: // 其他未明确支持的语言环境
// 默认使用中文资源作为回退方案
crm = new ComponentResourceManager(typeof(Resources.Resource_zh));
break;
}
// 2. 调用applyControl方法实际应用资源到控件
// 参数1:控件的类型名称(用于资源查找)
// 参数2:目标控件实例
applyControl(control.GetType().Name, control);
}
-
区域性判断:
-
使用
Thread.CurrentThread.CurrentCulture.Name
获取当前线程的区域性名称 -
根据不同的区域性代码选择对应的资源文件
-
-
资源管理器初始化:
-
每种语言对应一个独立的资源文件(如
Resource_en.resx
和Resource_zh.resx
) -
使用
ComponentResourceManager
来管理特定语言的资源
-
-
默认处理:
-
当遇到未明确支持的语言时,默认使用中文资源
-
这是一种常见的回退机制设计
-
-
资源应用:
-
最终调用
applyControl
方法将资源实际应用到控件 -
传递控件的类型名称用于资源键值查找
-
cs
/// <summary>
/// 递归应用资源到控件及其子控件
/// </summary>
/// <param name="topName">父控件名称路径(用于资源键前缀)</param>
/// <param name="control">当前要处理的控件对象</param>
private void applyControl(string topName, Control control)
{
// 处理表格布局面板(递归处理子控件)
if (control.GetType() == typeof(TableLayoutPanel))
{
// 遍历所有子控件
foreach (Control ctl in control.Controls)
{
// 应用资源:资源键格式为"父控件名.子控件名"
crm.ApplyResources(ctl, topName + "." + ctl.Name, Thread.CurrentThread.CurrentCulture);
// 递归处理子控件
applyControl(topName, ctl);
}
}
// 处理分组框(递归处理子控件)
else if (control.GetType() == typeof(GroupBox))
{
foreach (Control ctl in control.Controls)
{
crm.ApplyResources(ctl, topName + "." + ctl.Name, Thread.CurrentThread.CurrentCulture);
applyControl(topName, ctl);
}
}
// 处理UI面板(自定义面板控件,递归处理子控件)
else if (control.GetType() == typeof(UIPanel))
{
foreach (Control ctl in control.Controls)
{
crm.ApplyResources(ctl, topName + "." + ctl.Name, Thread.CurrentThread.CurrentCulture);
applyControl(topName, ctl);
}
}
// 处理UI标题面板(自定义控件,递归处理子控件)
else if (control.GetType() == typeof(UITitlePanel))
{
foreach (Control ctl in control.Controls)
{
crm.ApplyResources(ctl, topName + "." + ctl.Name, Thread.CurrentThread.CurrentCulture);
applyControl(topName, ctl);
}
}
// 处理UI分组框(自定义控件,递归处理子控件)
else if (control.GetType() == typeof(UIGroupBox))
{
foreach (Control ctl in control.Controls)
{
crm.ApplyResources(ctl, topName + "." + ctl.Name, Thread.CurrentThread.CurrentCulture);
applyControl(topName, ctl);
}
}
// 处理普通面板(递归处理子控件)
else if (control.GetType() == typeof(Panel))
{
foreach (Control ctl in control.Controls)
{
crm.ApplyResources(ctl, topName + "." + ctl.Name, Thread.CurrentThread.CurrentCulture);
applyControl(topName, ctl);
}
}
// 处理状态栏控件(特殊处理ToolStripItem集合)
else if (control.GetType() == typeof(StatusStrip))
{
var statusStrip = (StatusStrip)control;
// 遍历状态项(非标准Control类型)
foreach (ToolStripItem ctl in statusStrip.Items)
{
crm.ApplyResources(ctl, topName + "." + ctl.Name, Thread.CurrentThread.CurrentCulture);
}
}
// 处理选项卡控件(递归处理各TabPage)
else if (control.GetType() == typeof(TabControl))
{
var Tab = (TabControl)control;
foreach (TabPage ctl in Tab.TabPages)
{
crm.ApplyResources(ctl, topName + "." + ctl.Name, Thread.CurrentThread.CurrentCulture);
applyControl(topName, ctl);
}
}
// 处理单个选项卡页(递归处理子控件)
else if (control.GetType() == typeof(TabPage))
{
var Page = (TabPage)control;
foreach (Control ctl in Page.Controls)
{
crm.ApplyResources(ctl, topName + "." + ctl.Name, Thread.CurrentThread.CurrentCulture);
applyControl(topName, ctl);
}
}
// 处理数据网格视图(特殊处理列标题)
else if (control.GetType() == typeof(DataGridView))
{
var dataGridView = (DataGridView)control;
foreach (DataGridViewColumn ctl in dataGridView.Columns)
{
crm.ApplyResources(ctl, topName + "." + ctl.Name, Thread.CurrentThread.CurrentCulture);
}
}
// 处理特定窗体类型(需要特殊处理窗体资源)
else if (control.GetType() == typeof(frmAbout) || control.GetType() == typeof(FrmDB) || control.GetType() == typeof(frmLogin) || control.GetType() == typeof(FrmMainView) || control.GetType() == typeof(FrmSingleView)
|| control.GetType() == typeof(frmSystemSet) || control.GetType() == typeof(frmTCB) || control.GetType() == typeof(frmUserMananger) || control.GetType() == typeof(frmSystemChannelSet))
{
// 先应用窗体自身的资源(使用控件名作为资源键)
crm.ApplyResources(control, control.Name, Thread.CurrentThread.CurrentCulture);
// 处理窗体所有子控件(使用窗体名作为新的topName)
foreach (Control ctl in control.Controls)
{
crm.ApplyResources(ctl, topName + "." + ctl.Name, Thread.CurrentThread.CurrentCulture);
// 递归时使用窗体名作为新的topName
applyControl(control.Name, ctl);
}
}
// 默认处理(普通控件)
else
{
// 直接应用资源(使用父控件名.当前控件名作为资源键)
crm.ApplyResources(control, topName + "." + control.Name, Thread.CurrentThread.CurrentCulture);
}
}