65.9K
CodeProject 正在变化。 阅读更多。
Home

本地化的 Windows Forms 应用程序功能区控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (9投票s)

2010 年 9 月 17 日

CPOL

6分钟阅读

viewsIcon

96422

downloadIcon

5567

为 Windows Forms 应用程序创建本地化的功能区控件。

本地化示例

Be.HexEditor 示例

引言

在本文中,我将展示如何向 Windows Forms 应用程序添加本地化的 Ribbon 控件。我使用的是 Windows 7 中发布的 Windows 集成 Ribbon,但如果安装了相关的服务包和更新,它也适用于 Vista 和 Windows Server 2008。

要求

包含 Windows Ribbon Framework 的操作系统

  • Windows 7
  • 带有 SP2 和 Windows Vista 平台更新的 Windows Vista
  • Windows Server 2008 R2
  • 带有 SP2 和 Windows Server 2008 平台更新的 Windows Server 2008

此外,用于开发

  • 必须安装 Visual Studio 2010
  • 必须安装 Windows 7 SDK
  • 必须安装 RibbonGenerator 自定义工具(包含在下载文件“\RibbonLocalization\setup\RibbonGenerator.Setup.msi”中)

Windows Ribbon Framework 和 .NET Wrapper

市面上还有许多其他 Ribbon 库。其中大部分是商业版本——例如来自 Infragistics 的,但我想要一个免费的。另外,由于 Windows Forms 通常采用 Windows 控件,所以我决定使用 Windows 集成版本。

如果您想了解更多关于 Ribbon 的技术信息,请查阅 MSDN:Windows Ribbon Framework

Windows Ribbon 是一个非托管控件,提供了一个 COM 接口,可以使用自定义 COM 包装器在 .NET 中采用。我在 CodePlex (http://windowsribbon.codeplex.com/) 上找到了一个带有许多示例的合适解决方案。这是一项非常令人印象深刻的工作,但代码也是从 C++ 移植到 C# 的,因此包装器的对象模型不像 .NET。因此,我对其进行了一些重构,但首先让我们看看如何将 Ribbon 添加到您的应用程序中。

使用 Ribbon

在阅读本文之前,您应该熟悉 CodePlex 上的原始 .NET Wrapper。

现在我将向您展示如何使用我重构的 .NET Wrapper 和 RibbonGenerator 自定义工具将 Ribbon 添加到您的 Windows Forms 应用程序中。请不要忘记考虑上述软件要求以及必须安装 RibbonGenerator 自定义工具。

添加 Ribbon XAML (RibbonMarkup.xml) 和本地化文件 (RibbonMarkup.resx)

有关 Ribbon XAML 的更多详细信息,请参阅MSDN 或上述CodePlex 示例

  1. Ribbon 文本的本地化信息。文件名必须与 Ribbon XAML 文件相同
  2. Ribbon XAML 文件
  3. 由自定义工具生成的 Ribbon 嵌入式资源
  4. 由自定义工具生成的 Ribbon 日志文件
  5. 用于生成 *3 和 *4 的自定义工具名称

本地化工作原理

Ribbon UI 信息必须在 Ribbon XAML 文件中定义,本地化信息在 ResX 文件中定义。自定义工具会在 XAML 文件中查找“{Resource”标签,并使用 ResX 文件中的信息进行替换。会生成多个 .ribbon 文件——每个 ResX 文件一个。

使用 {Resource:<ResourceKey>} 符号在 Ribbon XAML 中定义本地化文本。

将本地化资源添加到 ResX 文件

将 Ribbon 控件添加到窗体

最简单的方法是将 Ribbon.dll 添加到您的工具箱中。您可以在下载文件中找到它:“\bin\Ribbon.dll

从工具箱拖放

在 Visual Studio 设计器中,Ribbon 控件将如下所示

在 Ribbon 控件属性中指定 Ribbon UI

在 Ribbon 控件的属性中,我们必须指定由 RibbonGenerator 自定义工具生成的“.ribbon”文件。该文件必须是应用程序中的嵌入式资源。您可以在 Ribbon XAML 文件下找到它。

结果看起来像...

让我们看看结果如何。在我们的示例中,我们有两个 Ribbon 资源:默认和德语。

按默认文化本地化

指定文化信息

为了使用本地化的 Ribbon,必须通过更改当前线程的 CurrentCulture 属性来设置应用程序的当前文化。

按德语文化本地化

重构 .NET Wrapper

我重构了原始的 .NET Wrapper,使其更像 .NET,因为它有一些我不喜欢的设计问题

  • 未实现本地化支持
  • 创建了一个包含 Ribbon 资源的独立非托管 DLL,必须将其部署在应用程序目录中
  • 包含 Ribbon 的窗体必须实现一个名为 IRibbonForm 的接口
  • Ribbon 类不派生自 Control
  • Ribbon 对象必须直接在窗体代码中初始化
  • 通常不支持 Visual Studio 设计器
  • Ribbon DLL 是使用预构建事件创建的,因此每次应用程序构建时都会重新创建 ribbon。
  • 自动构建和部署可能会带来很多麻烦

为了解决这个问题,我对 .NET Wrapper 进行了一些更改,并创建了 RibbonGenerator 自定义工具

  • Ribbon UI(“.ribbon”)现在作为嵌入式资源包含在内,无需作为单独的 DLL 部署
  • 每个本地化版本都有一个嵌入式资源文件,以支持多语言
  • Ribbon 类现在派生自 Control 类,以添加最少的 Visual Studio 设计器支持并使 IRibbonForm 接口过时
  • “.ribbon”文件只会在 RibbonGenerator 自定义工具运行时更新。
  • RibbonGenerator 自定义工具还考虑 ResX 文件以添加本地化支持。

修改后的 .NET Wrapper (Ribbon.dll)

我想向您简要介绍一下我所做的更改。

使 Ribbon 类派生自 Control

Ribbon 类现在派生自 Control 类。优点是对象模型更像 .NET,并且可以使用设计器。此外,包含 Ribbon 的窗体无需实现 IRibbonForm 接口。

使 IRibbonForm 接口过时

原始版本的 IRibbonForm 接口必须实现,原因有两个:必须检索窗体的句柄,并且必须在 Ribbon 高度更改时通知窗体以更新锚定控件的位置。现在在我的 .NET Wrapper 中,高度更新强制在 Ribbon 控件上,并且控件本身可以返回窗体的句柄。

[Browsable(false), DesignerSerializationVisibility
		(DesignerSerializationVisibility.Hidden)]
public IntPtr WindowHandle
{
get
{
var form = this.Parent as Form;
return form.Handle;
}
}

禁用渲染

.NET Ribbon 控件充当占位符,并将 Windows Ribbon 注入窗体中。它不包含任何渲染信息,但知道 Ribbon 的高度。因此,我们可以禁用控件渲染。

this.SetStyle(ControlStyles.UserPaint, false);
this.SetStyle(ControlStyles.Opaque, true);

Ribbon 控件始终停靠在窗体顶部,因此我们在构造函数中设置了这一点,并覆盖 Dock 属性以禁用更改。

public Ribbon()
{
	base.Dock = DockStyle.Top;

....

[DefaultValue(typeof(DockStyle), "Top")]
public override DockStyle Dock
{
	get
	{
		return base.Dock;
	}
	set
	{
	}
}

Ribbon 控件正在加载 UI

Ribbon 控件读取嵌入式资源文件并将其保存到用户临时目录以加载 Ribbon UI。

void InitFramework(string ribbonResource, Assembly ribbonAssembly)
{
	string path = Path.Combine(Path.GetTempPath(), "RibbonDlls");
	_tempDllFilename = Path.Combine(path, Path.GetTempFileName());
	var buffer = GetLocalizedRibbon(ribbonResource, ribbonAssembly);

	File.WriteAllBytes(_tempDllFilename, buffer);

	// if ribbon DLL exists, use it
	if (File.Exists(_tempDllFilename))
	{
		// load ribbon from ribbon DLL resource
		InitFramework(DefaultResourceName, _tempDllFilename);
	}
}

用于生成 .ribbon 文件的 RibbonGenerator 自定义工具

此自定义工具与 CodePlex 示例中的预构建事件脚本功能相同。简而言之:它生成“.ribbon”文件。更详细地讲:此自定义工具为每个 .ResX 文件创建一个 .ribbon 文件,以支持本地化。它需要系统上存在 Windows 7 SDK 二进制工具,因为它只创建和执行批处理文件。批处理文件的模板将在首次运行时在用户的应用程序数据文件夹中创建。此模板可以由您自定义。

Template.bat

如果 RibbonGenerator 自定义工具在您的系统上不起作用,但所有要求都已安装,则可能需要自定义 template.bat 文件。

"C:\Program Files\Microsoft SDKs\Windows\v7.0\bin\UICC.exe"
	"{XmlFilename}" "{BmlFilename}" /res:"{RcFilename}"
"C:\Program Files\Microsoft SDKs\Windows\v7.0\bin\rc.exe" /v "{RcFilename}"
cmd /c "("%VS100COMNTOOLS%..\..\VC\bin\vcvars32.bat") &&
	("%VS100COMNTOOLS%..\..\VC\bin\link.exe"
	/VERBOSE /NOENTRY /DLL /OUT:"{DllFilename}" "{ResFilename}")"

如您所见,template.bat 包含在自定义工具运行时将执行的进程步骤。如果您删除 template.bat 文件,它将在下次运行时重新创建。为确保 RibbonGenerator 正常工作,请先安装 Windows 7 SDK,否则请删除或自定义 template.bat 文件。

关注点

我一直在研究 CodePlex 库,并考虑在 Be.HexEditor 的未来版本中实现 Ribbon。我发现本地化在短时间内实现并不容易,所以它可能会对您有所帮助。

历史

  • 2010 年 9 月 16 日:初始发布
© . All rights reserved.