Localization Sample
Be.HexEditor Sample
Introduction
In this article, I will show how you can add a localized Ribbon control to a Windows Forms application. I'm using the Windows integrated Ribbon that releases with Windows 7, but is also available for Vista and Windows Server 2008, when relevant service packs and updates are installed.
Requirements
Operating systems containing Windows Ribbon Framework
- Windows 7
- Windows Vista with SP2 and Platform Update for Windows Vista
- Windows Server 2008 R2
- Windows Server 2008 with SP2 and Platform Update for Windows Server 2008
Additionally for Development
- Visual Studio 2010 must be installed
- Windows 7 SDK must be installed
- RibbonGenerator custom tool must be installed (Included in download "\RibbonLocalization\setup\RibbonGenerator.Setup.msi")
Windows Ribbon Framework and .NET Wrapper
There are many other Ribbon libraries out there. Most of them are commercial versions - for example from Infragistics, but for me I wanted a free one. Also because Windows Forms adopts Windows controls in general, I decided to use the Windows integrated one.
If you want to get more technical information about the Ribbon, look into MSDN: Windows Ribbon Framework.
Windows Ribbon is an unmanaged control offering a COM interface that can be adopted in .NET using custom COM wrappers. I found an appropriate solution at CodePlex (http://windowsribbon.codeplex.com/) with many samples. It's a very impressive work, but also the code is transportation from C++ to C# and therefore the object model of the wrapper is not .NET like. For that reason, I refactored it a little bit, but first let's take a look at how the Ribbon can be added to your application.
Using the Ribbon
Before you read this, you should be familiar with the original .NET Wrapper on CodePlex.
Now I will show you how you can use my refactored .NET Wrapper with the RibbonGenerator
custom tool to add a Ribbon to your Windows Forms application. Please do not forget to consider the software requirements from above and that the RibbonGenerator
custom tool must be installed.
Add Ribbon XAML(RibbonMarkup.xml) and Localization Files (RibbonMarkup.resx)
For more details about Ribbon XAML, look at MSDN or the CodePlex samples mentioned above.
- The localization information for the Ribbon text. The file name must be equal to the Ribbon XAML file
- The Ribbon XAML file
- The Ribbon embedded resource generated by custom tool
- The Ribbon log file generated by custom tool
- The custom tool name to generate *3 and *4
How Localization Works
Ribbon UI information must be defined in the Ribbon XAML file and localization information in the ResX file. The custom tool is searching for "{Resource
" tags in the XAML file and replacing it using information from ResX file. Multiple .ribbon files are generated - one for each ResX file.
Define localized text inside Ribbon XAML using {Resource:<ResourceKey>} notation.
Add localized resources to ResX file
Adding the Ribbon Control to your Form
The easiest way is to add the Ribbon.dll to your toolbox. You can find it in the download looking there: "\bin\Ribbon.dll"
Use drag and drop from toolbox
In the Visual Studio designer, the Ribbon control will look like this:
Specify the Ribbon UI in the Ribbon control properties
In the properties of the Ribbon control, we must specify the ".ribbon" file generated by the RibbonGenerator
custom tool. The file must be an embedded resource in your application. You can find it under your Ribbon XAML file.
Result looks like...
Let's see how the result looks like. In our sample, we have two Ribbon resources: Default and German.
Localized by default culture
Specify culture information
In order to use a localized Ribbon, the application's current culture must be set by changing the CurrentCulture
property of the current thread.
Localized by German culture
Refactoring the .NET Wrapper
I refactored the original .NET Wrapper to be more .NET like, because it has some design issues I dislike:
- Localization support is not implemented
- A separate unmanaged DLL containing the Ribbon resources is created and must be deployed within the application directory
- A form containing the Ribbon must implement an interface called
IRibbonForm
Ribbon
class does not derive from Control
class
Ribbon
object must be initialized directly in Form code
- Visual Studio designer is not supported generally
- Ribbon DLL is created using Pre-build event, so ribbon is recreated every time the application builds.
- Automatic build and deployment can make a lot of trouble
To solve that, I did some changes to the .NET Wrapper and created the RibbonGenerator
custom tool:
- The Ribbon UI (".ribbon") is included as embedded resource now and must not be deployed as separate DLL
- There is one embedded resource file for each localized version to support multi-languages
Ribbon
class derives from Control
class now to add minimum Visual Studio designer support and to make IRibbonForm
interface obsolete
- The ".ribbon" file will only be updated when the
RibbonGenerator
custom tool runs.
- The
RibbonGenerator
custom tool also considers ResX files to add localization support.
The Modified .NET Wrapper (Ribbon.dll)
I want to give you a small technical overview of the changes I have made.
Make Ribbon Class Deriving from Control
The Ribbon
class now derives from Control
class. The advantage is that the object model is more .NET like and the designer can be used. Also, no IRibbonForm
interface must implemented by the form containing the Ribbon
.
Making IRibbonForm interface obsolete
IRibbonForm
interface of the original version had to be implemented for two reasons: The form's handle must be retrieved and the form must be notified on Ribbon height changes to update the position of anchoring controls. Now in my .NET Wrapper, the height update is forced on the Ribbon control and the control itself can return the form's handle.
[Browsable(false), DesignerSerializationVisibility
(DesignerSerializationVisibility.Hidden)]
public IntPtr WindowHandle
{
get
{
var form = this.Parent as Form;
return form.Handle;
}
}
Disable Rendering
The .NET Ribbon control works as a place holder and injects the Windows Ribbon in the form. It does not contain any rendering information, but knows the height of the Ribbon. Therefore, we can disable control rendering.
this.SetStyle(ControlStyles.UserPaint, false);
this.SetStyle(ControlStyles.Opaque, true);
The Ribbon is docking always on top of the form, so we set that in the constructor and override the Dock property to disable changes.
public Ribbon()
{
base.Dock = DockStyle.Top;
....
[DefaultValue(typeof(DockStyle), "Top")]
public override DockStyle Dock
{
get
{
return base.Dock;
}
set
{
}
}
Ribbon Control is Loading the UI
The Ribbon control reads an embedded resource file and saves that into the user's temp directory to load the 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 (File.Exists(_tempDllFilename))
{
InitFramework(DefaultResourceName, _tempDllFilename);
}
}
RibbonGenerator Custom Tool for .ribbon File Generation
The custom tool does the same job as the pre-build event script in the CodePlex samples. In short: It generates the ".ribbon" files. More: The custom tool creates one .ribbon file for each .ResX file to support localization. It needs Windows 7 SDK binary tools be present on the system, because it just creates and executes batch files. The template of the batch file will be created on the first run in the user's app data folder. This template can be customized by you.
Template.bat
If the RibbonGenerator
custom tool will not work on your system but all requirements are installed, probably you need to customize the template.bat file.
"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}")"
As you can see, the template.bat contains process steps that will execute while the custom tool is running. If you delete the template.bat file, it will be recreated on the next run. To ensure, that the RibbonGenerator
will work correctly, install the Windows 7 SDK first, otherwise delete or customize the template.bat file.
Points of Interest
I was playing with the CodePlex library and thinking about implementing the Ribbon in future versions of Be.HexEditor. I figured out that localization is not so easy to implement in a short time, so probably it will be helpful to you.
History
- 16th September, 2010: Initial post