Click Here to Install Silverlight*
Middle EastChange|All Microsoft Sites
Microsoft

Implementing Mirror-Aware Controls for Windows Application with Visual Studio .NET

Content



Introduction

Visual Studio .NET provides a wide support of Arabic, in application development. Yet, Windows Forms do not support mirroring directly, as they do with the RightToLeft property. Meanwhile, to enable this feature, Windows Forms do give developers the capability to customize the appearance and functionality of the controls through inheritance. This discussion only involves managed code, since you may not need the hassle of unmanaged code. This article will explain the meaning of mirroring and investigate the ability to extend existing controls to add the mirroring property.

What is Mirroring?

Mirroring is a term used to specify right-to left (RTL) layout, which identifies how text and GDI objects are laid out in a window. Therefore, it gives a perfect right-to-left (RTL) look and feel to the UI. For Windows 98 and Windows Me, this technology was only available on Arabic enabled and localized operating systems. However, on all Windows 2000 varieties and later, are already mirroring aware. Mirroring is in fact nothing else than a coordinate transformation:

The window layout applies to text but also affects the other GDI elements of the window, including bitmaps, icons, the location of the origin, buttons, cascading tree controls, and whether the horizontal coordinate increases as you go left or right. For example, after an application has set RTL layout, the origin is positioned at the right edge of the window or device, and the number representing the horizontal coordinate increases as you move left. However, not all objects are affected by the layout of a window. For example, the layout for dialog boxes, message boxes, and device contexts is not associated with a window. However, changing to a RTL layout is not supported for windows that have the style CS_OWNDC. For a DC with the GM_ADVANCED graphic mode the behavior may be inconsistent with what you need. It reverses text as you would see later.


How to Enable Mirroring of your Control?

The steps to mirror your controls:

  1. Create a new custom control class. Set it to inherit from the control you wish to mirror.
  2. Create the Mirrored property under the category Appearance.
  3. Override the CreateParams method of the control's class, which gives you the ability to set the desired control styles while the control is still being created. If the Mirrored property is set to yes then add the RTL layout to the control and if not keep the same styles.
  4. Create a test form, and add a reference to the previously created mirrored control; add the new control to the form.

Now, you have the Mirrored property available in the properties window and you can use it as needed.

Note
The Windows form is considered a control since it is derived from the System.Windows.Forms.Control class.

The two window styles you would need:

  • WS_EX_LAYOUTRTL (400000 hexadecimal)
    This style sets the layout to RTL. Therefore, the horizontal origin is the right edge and increasing horizontal value would advance to the left.
  • WS_EX_NOINHERITLAYOUT (100000 hexadecimal)
    This style prevents the layout from being inherited, by the child windows because not all controls need RTL layout. Therefore, you need to enforce the controls on the forms will not get mirrored. Imagine that you mirror text and then the letters would appear in reversed order!!! This behavior is caused because the label control device context is in the GM_ADVANCED mode.
    These figures show the effect of removing this flag:

 
Original Form : both the WS_EX_LAYOUTRTL and the WS_EX_NOINHERITLAYOUT are set Form without setting the WS_EX_NOINHERITLAYOUT

These two styles are not defined in the system and therefore you need to use their hexadecimal values to use them, as shown later.
The following is a list of the controls, which can now support mirroring and whether they need to allow inheritance of the layout.

Control Should not allow layout inheritance
Listview No
Panel Yes
Statusbar Yes
Tabcontrol Yes
TabPage Yes
Toolbar No
TreeView No
Form Yes
Splitter Yes


The following are two examples of the inherited custom controls.

Example 1: Mirrored Treeview control. The same code may be used with the Listview, and Toolbar controls. You should change the inheritance to the appropriate control.

[Visual Basic]
Imports System.ComponentModel
Public class RTLTreeView
Inherits System.Windows.Forms.TreeView 'Inherits from the standard TreeView control
'Define your style
Const WS_EX_LAYOUTRTL = &H400000
Private _RTL As Boolean = False
'Mirrored property to test the RTL order
<Description ("Change to the right-to-left layout."), _
DefaultValue(False),Localizable (True), _
Category("Appearance")> _ Public Property Mirrored() As Boolean
  Get
    Return _RTL
  End Get
  Set(ByVal Value As Boolean)
    'Set the new value if it changed
    If _RTL <> Value Then
      _RTL = Value
      MyBase.OnRightToLeftChanged(EventArgs.Empty)
    End If
  End Set
End Property


Protected Overrides ReadOnly Property CreateParams()As
System.Windows.Forms.CreateParams
  Get
    'Retrieve the CreateParams class to change the style
    Dim CP As System.Windows.Forms.CreateParams
    CP = New System.Windows.Forms.CreateParams()
    CP = MyBase.CreateParams
      'If the control needs RTL add these styles
      If Mirrored Then
        CP.ExStyle = CP.ExStyle Or WS_EX_LAYOUTRTL
      End If
      Return CP
    End Get
  End Property
End Class



[C#]
public class RTLTreeView : System.Windows.Forms.TreeView
{     const int WS_EX_LAYOUTRTL = 0x400000;
    private bool _RTL = false;

[Description("Change to the right-to-left layout."),DefaultValue(false),
Localizable(true),Category("Appearance"),Browsable(true)]
public bool Mirrored
{
    get
    {
        return _RTL;
    }
    set
    {
        if (_RTL != value)
        _RTL = value;
        base.OnRightToLeftChanged(EventArgs.Empty);
    }
}
protected override CreateParams CreateParams
{
    get
    {
        CreateParams CP;
        CP = base.CreateParams;
        if (this.Mirrored)
        CP.ExStyle = CP.ExStyle | WS_EX_LAYOUTRTL;
        return CP;
    }
}
//Rest of Tree View Code

Example 2: Mirrored Windows Form, the following example differs slightly from the previous one in that the style is set to WS_EX_NOINHERITLAYOUT.

[Visual Basic]
Public Class RTLForm
    InheritsSystem.Windows.Forms.Form
    'Define your styles
    Const WS_EX_LAYOUTRTL = &H400000
    Const WS_EX_ NOINHERITLAYOUT = &H100000
        .
        .
        .
      If bMirror Then
      cp.ExStyle = cp.ExStyle Or WS_EX_LAYOUTRTL Or
      WS_EX_NOINHERITLAYOUT
      End If
        .
        .
        .
End Class



[C#]
Public Class RTLForm
    Inherits System.Windows.Forms.Form
{
    Const WS_EX_LAYOUTRTL = &H400000
    Const WS_EX_NOINHERITLAYOUT = &H100000
    .
    .
    .
    If (bMirror)
    CP.ExStyle = CP.ExStyle | WS_EX_LAYOUTRTL | WS_EX_NOINHERITLAYOUT;
    .
    .
    .
}

However, this solution is not applicable to all controls that may require mirroring. Although, the ProgressBar control needs mirroring, yet the class is not inheritable and so we can't implement this method. Another class that is not inheritable is the Imagelist control class.

How to Mirror your Images?

You can mirror your images very easily by flipping the image over its horizontal axis using one line of code:

[Visual Basic]
Img.RotateFlip(RotateFlipType.RotateNoneFlipX)

[C#]
Img.RotateFlip(RotateFlipType.RotateNoneFlipX);

The Imagelist control is used with a number of controls mainly the Treeview, Listview and ToolBar. When you set the RTL layout of these controls the images are also mirrored as shown in this figure.


This is a toolbar with an Imagelist control that appear flipped.

If you are sure that all your application has RTL layout, then you have two alternatives. First method, flip your images horizontally at rendering time. Therefore as the control is mirrored it would display the images properly. Second method, you may add the code for the image flipping. You may place this code in the form load method.

[Visual Basic]
  'Check that you have a valid ImageList
  If Treeview1.ImageList() Is Nothing Then
      Debug.WriteLine ("You don't have an Imagelist")
  Else
      Dim i As Integer
      Dim TempImg As Image
      'Go through all the elements
      For i = 0 To i = RtlTreeView1.ImageList.Images.Count
          'Get the item
          TempImg = RtlTreeView1.ImageList.Images.Item(i)
          'Flip the item horizontally
          TempImg.RotateFlip(RotateFlipType.RotateNoneFlipX)
          'Set the item again
          RtlTreeView1.ImageList.Images.Item(i) = TempImg
      Next
  End if



[C#]
int i;
Image tempImg;
//Go through all the elements
for(i = 0; i < rtlTreeView1.Nodes.Count;i++)
{
    //Get the item
    tempImg = rtlTreeView1.ImageList.Images[i];
    //Flip the item horizontally
    tempImg.RotateFlip(RotateFlipType.RotateNoneFlipX);
    //Set the item again
    rtlTreeView1.ImageList.Images[i] = tempImg;
}

Yet, this solution is not suitable for international application. As mentioned before, the Imagelist control class is not inheritable and therefore you do not have control over the flipping of class elements, within the class. Another disadvantage of using this method is that the Imagelist control may be used with a number of controls, not only one, therefore you have to know the effect of flipping images on the other controls. An appropriate solution for international applications is to create your images which are indifferent to mirroring. That means it can be displayed from right-to-left or from left-to-right without changing its look. Remember, you should not use text in images for international applications.

However, the image flipping problem doesn't apply to the PictureBox control because it is created as a separate control. So feel free to add pictures on your forms and they will be displayed correctly as long as you set the no inherit layout style for its parent forms.

Conclusion

This article provided an overview of how to enrich your application with a better feel of the RTL language requirements. You may use the provided assembly to enhance your program with minimal programming involved. All you need to do is to include this assembly in your project and inherit from the controls. The Form, Panel, ListView, SatusBar, TabControl, TabPage, ToolBar and Treeview controls are now mirror aware.

Downloads

Each solution consists of two projects, the main application and an assembly. The application uses the controls with the Mirrored property. The assembly contains the inherited controls. You may include this assembly in your application and use it directly.



System Requirements

Platforms: Arabic Windows 98 (enabled and localized), Arabic Windows Millennium Edition (enabled and localized), Windows 2000, Windows XP Home Edition, Windows XP Professional, Windows .NET Server 2003 family.

Environment: Visual Studio .NET, the .NET framework.




©2015 Microsoft Corporation. All rights reserved. Contact Us |Terms of Use |Trademarks |Privacy Statement
Microsoft