Introduction
Windows Forms Controls
Setting RightToLeft according to the UICulture
Changing the Input Language
Text Rendering
Number Substitution
You are sometimes faced with some challenges to develop Arabic applications.
Most of these issues are due to the fact that Arabic is a right-to-left (rtl)
language, where the letters are written from right-to-left, unlike most
scripts, where letter are written from left-to-right. I n Visual Studio 2005 we
bring you more Arabic and rtl support.
In this paper, you will explore the new enhanced rtl features introduced by
Visual Studio 2005. First, we'll highlight the new improved Windows Forms
Controls. This includes several interesting properties. Second, we'll examine
text rendering in Windows Forms applications.
But before you begin, you need to be familiar with the importance of setting
your regional settings in Windows. Especially if you are working in
non-Unicode, if your work is only Unicode, then you don't need to worry about
these settings. However, in many cases you use non-Unicode data and get puzzled
with question marks and garbage characters (high-Ansi). If you are not familiar
with the Windows Regional and Languages settings, then please take some time
and read about it here
Arabic Windows Settings .

Windows Forms
Controls
Windows Forms controls are the basic elements of a Windows Applications. You
will find improvement in the Windows Forms right-to-left (rtl) features. In new
controls, such as the TableLayoutPanel , FlowLayoutPanel
, SplitContainer , StatusStrip , ToolStrip
and MaskedTextBox etc… there is support for rtl.
Simply set RightToLeft =Yes and it would set the reading
order, alignment and the layout of these controls. While in existing common
controls, such as treeview , Listview , MonthCalendar
etc... You have a new property to add the rtl layout. Simply set both
RightToLeftLayout =true and RightToLeft =yes and
you get full rtl layout, there may be some limitations but the development
experience is easier.

RightToLeft and RightToLeftLayout
are highlighted in the properties Window
Let's examine the main property rtl support, RightToLeft . The
RightToLeft property specifies three main things:
First, the reading order is rtl. This is important to
determine how neutral and numbers would behave. For example, if the textbox
contains some text ending with a colon (":") it would be on the left of the
text in case of RightToLeft=Yes but would be on the right otherwise. The same
would happen with other neutral characters parentheses, full stop or brackets.
Second, the text alignment is on the opposite side. This
means if text is "Left" aligned then it would be "Right" aligned for Arabic.
Therefore, the TextAlign property shows the opposite value in
case of RightToLeft . If you enforce "right" alignment it
would be displayed to the "left" and vice versa. The reason for this behavior
is that the TextAlign property is based on the "near" and
"far" coordinates rather than absolute "left" or "right".
Third, the layout of the control might also be affected.
This means the UI elements are displayed from the right edge to the left edge
instead of placing controls from the left to right.
New controls in Visual Studio 2005 respect the above aspects of the RightToLeft
property. However, in some older controls we added a new property to enforce
the rtl layout, through RightToLeftLayout property. For more
information about the RightToLeftLayout , check this article
What is RightToLeftLayout?
The following topics explain how Windows Forms applications support rtl and
specifically Arabic in more details.

Container controls are controls that visually contain other controls. For
example Panel , GroupBox When you set
RightToLeft=Yes to a Panel , GroupBox , TabPages
, you set the reading order to rtl but the layout of the controls
doesn't change. This is similar to previous versions of Visual Studio .NET.
The following controls don't have rtl layout, when RightToLeft=yes:
Panel
GroupBox
TabPages
SplitContainerPanels
You need to rearrange the items in these controls to flow from RightToLeft
manually because these controls don't have rtl layout.
This is an example of rearranging the layout of the controls programmatically at
runtime, without changing the Form at design-time:
int
NumberOfControls = ParentPanel.Controls.Count;
for
(
int
i=0; i<NumberOfControls;i++)
{
ParentPanel.Controls[i].Left = ParentPanel.Width -
(ParentPanel.Controls[i].Left + ParentPanel.Controls[i].Width);
}
This code iterates into all the controls in the ParentPanel and changes their
location to be rtl oriented.
For more complex layout scenarios, Windows Forms 2.0, provides SplitContainer
, TableLayoutPanel and FlowLayoutPanel
. These controls are similar to panel controls to host other controls. The TableLayoutPanel
and FlowLayoutPanel controls supply advanced layout
engine to handle more sophisticated layout needs.
TableLayoutPanel is similar to the table in html. It allows you
to define rows and columns that you can set the size automatically in three
ways: AutoSize , Percent and Absolute
. You have to be careful when dealing with an empty cell while the size is set
to AutoSize .
The TableLayoutPanel supports rtl. Simply, set RightToLeft=Yes
and the columns would rearrange from right-to-left. This means, the
first column would start from the right and the next column is on its left.
FlowLayoutPanel is more suitable when you want a Form and its
controls to resize according to the display area similar to HTML Web pages. You
can specify the direction in which the controls should be moved during form
resize by setting its FlowDirection property to one of four
values: LeftToRight , TopDown , RightToLeft
, or BottomUp . Don't be confused of the RightToLeft
direction this is not the same as setting RightToLeft =Yes.
Setting RightToLeft =Yes also affects the child controls and
set it's property as well as affects the reading order of the text in the
controls.
Like the TableLayoutPanel , the FlowLayoutPanel
also supports rtl. Simply set RightToLeft =Yes and the items
would flow from right-to-left even though the FlowDirection is still set to
LeftToRight. Actually the FlowDirection is reversed when RightToLeft
=Yes, similar to the TextAlign property we discussed
earlier.
The SplitContainer provides two panels separated by a movable
bar. It is designed to replace the Splitter control and give a richer
design-time and run-time experience. In the case of vertical panels,
when you set the SplitContainer.RightToLeft=Yes. The Panels are reversed. The
First panel is place on the right while the second panel is placed on the left.
However, the contents of each panel don't flow from right-to-left. To achieve
this you can dock a TableLayoutPanel or a FlowLayoutPanel into these
SplitContainer's panels.
This shows the SplitConatiner while RightToLeft=Yes:


Let's examine the Form. The Form is the main element in your application, which
contains your controls. You can add rtl support to your Form by simply setting
RightToLeft but you will get a better behavior when you set RightToLeftLayout
too, it depends on your needs.
There are simple forms and multiple document interface (MDI) parent form but
let's start with the simple Form.
First, check this simple Form, before we add rtl to it.

|
The original form, before rtl.
|
Second, let's set RightToLeft to Yes and examine the form:

|
The Form, when RightToLeft is yes
|
The result is that the title is aligned to the right but the control boxes are
still in the same location as when rtl= no. The containing controls inherit
RightToLeft=Yes, if they were set to inherit , which is the
default.
Third, let's give it a more advanced rtl look and set RightToLeftLayout
to true:

|
The Form, when RightToLeft is yes and
RightToLeftLayout =true
|
The result is that the title is aligned to the right and the control boxes are
displayed in an rtl fashion. In addition to the child's controls are laid from
the right to left. However, the containing controls don't inherit the RightToLeftLayout
value.
Everyone agrees that the title is much better once you set RightToLeftLayout
too but some people may not accept the reordering of the controls. This would
depend on your application.
There is a simple workaround to keep your layout and still get an rtl title. You
can fill the Form's client area with a Panel, so that it is your controls'
parent and so the control's layout would not be affected by setting the RightToLeftLayout
property.
This would be final result for your Form:

|
The Form, When RightToLeft is Yes and
RightToLeftLayout =true and a docked Panel containing the
controls.
|
Note: If you added the controls on the Form before the Panel, you may need to
manually change the control's parent to the Panel instead of the Form.
Now let's examine the MDI Form. The MDI Form contains child Forms and these
Forms are cascaded from left to right by default. To cascade child Forms from
the right corner to the left of the parent's form you need to set RightToLeftLayout
=true for the child forms too. However, this doesn't mean that the
child Forms will inherit the RightToLeftLayout , you need to
set this property individually to child Forms.
Note. If you need to set the MDI background image, it's recommended not to set
RightToLeftLayout=true .
The figure below shows an MDI Parent form with RightToLeftLayout=true:


When I talk about Strip controls, I am actually referring to MenuStrip
, ToolStrip , StatusStrip , and ContextMenuStrip
controls. These replace the troubled MainMenu , ToolBar
, StatusBar , and ContextMenu .
These controls had numerous problems with rtl support so it's great news you
got the new strip controls. Even though MainMenu , ToolBar
, StatusBar , and ContextMenu are not
included by default in the Visual Studio Toolbox, they are still included in
the .NET Framework, primarily for backwards compatibility.
The Strip controls provide a contemporary look of Office 2003 and Windows
themes. They all share the same code base and thus provide the same handling to
all the Strip controls. In addition to the improved design-time experience and
ability to host a rich set of child controls, such as dropdownlists
, textboxes and more.
And the main benefit is that they support proper RTL.
When you set RightToLeft=Yes, your strip control items are automatically
rearranged from right-to- left. Even more, there is an additional property for
the rtl images. RightToLeftAutoMirrorImage resolves common
issues with rtl users, who use directional images, an example of directional
images are the arrows with next \previous images. In this specific case, you
need your image to be mirrored too. This property mirrors automatically the
ToolStripItem image when the RightToLeft property
is set to Yes . Otherwise it doesn't have an affect on your
item.
The ToolStripProgressBar also has the RightToLeftLayout
property to se the progress layout properly.
Below is a screenshot of a mirrored Question Mark, after setting
RightToLeftAutoMirrorImage = True, while RightToLeft=Yes.

This is the code snippet to mirror the Help image:
// helpToolStripButton
//
this
.helpToolStripButton.DisplayStyle = System.Windows.Forms.
ToolStripItemDisplayStyle
.Image;
this
.helpToolStripButton.Image = ((System.Drawing.
Image
)(resources.GetObject(
"helpToolStripButton.Image"
)));
this
.helpToolStripButton.RightToLeftAutoMirrorImage =
true
;
this
.helpToolStripButton.Text =
"He&lp"
;

The MaskedTextBox class is an enhanced TextBox
control that enables you to apply a mask for accepting user input. Mainly, the
MaskedTextBox was designed to retain most of the functionality of
the Masked Edit control in Visual Basic 6.0.
In addition to this, we have a new property in the MaskedTextBox
, the Culture property, this will enable you to select between
different masks in different cultures. Try to change the Culture
property and check the different masks that you can choose from. Below is a
list of masks you can choose from, default culture and Arabic culture:
| Culture |
Masks |
Date Format |
| (default) |
Numeric (5-digits) |
12345 |
| Phone Number |
(574) 555-01234 |
| Phone Number no area code |
555-01234 |
| Short date |
12/11/2003 |
| Short date and time(US) |
12/11/2003 11:20 |
| Social Security number |
000-00-1234 |
| Time (European\Military) |
23:20 |
| Time (US) |
11:20 |
| Zip Code |
98052-6399 |
| Arabic |
Phone Number |
(012) 345-6789 |
| (ar) |
Phone Number no area code |
123-4567 |
| Short date |
26 /10 /2005 |
| Short date and time(US) |
26 /10 /2005 11:20 |
| Social Security number |
123-45-6789 |
| Time |
2:30 |
| Time (24 Hours) |
14:30 |
Note: By default, the culture property is detected from your Windows locale
settings. You can change this property as you need.
The default "Short date" mask contains spaces between the number and the slash
("/"). This is to insure that dates are displayed properly, even when the
MaskedTextBox is RightToLeft. Check this example of the same date in these
different cases:

If you are not satisfied with the default "short date" mask for Arabic cultures,
you can specify the traditional "short date" mask or even specify your own
mask.
Besides these existing masks, you can also define your own mask depending on
your needs, as follows:
maskedTextBox1.Mask = "00000-9999";

Some common controls didn't layout properly, even when you set RightToLeft
= Yes. However, now, you can add rtl layout to the following controls by simply
setting RightToLeftLayout & RightToLeft :
TreeView
ListView
MonthCalendar
DateTimePicker
Progressbar
TabControl
TrackBar
For the above controls, you can set RightToLeftLayout for each
control but this property can't be inherited. This might appear more difficult
to use than the RightToLeft but for a good cause. There is no
illusion that this property is simple and trouble free. It has its limitation
and you should be aware of them once you set RightToLeftLayout
. For more information refer to the online help.
Another issues, you should be aware that, RightToLeftLayout doesn't
have an affect on a control until RightToLeft is set to yes
too.
You need to be aware of that the images appear mirrored by default, when you set
RightToLeftLayout =true.
For more information about the RightToLeftLayout , check this
article What
is RightToLeftLayout?

When you develop multi-lingual application you are bound to change your Forms
direction to rtl programmatically at runtime.
There are several techniques to detect the OS language and display your
application with the appropriate language and rtl settings, here are some
ideas:
The old technique, you would need to detect your UIculture and change the
RightToLeft value accordingly.
public static bool
CultureInfoIsRightToLeft()
{
string
cultureInfoLanguage = System.Globalization.CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
return
cultureInfoLanguage ==
"ar"
||
cultureInfoLanguage ==
"div"
||
cultureInfoLanguage ==
"fa"
||
cultureInfoLanguage ==
"syr"
||
cultureInfoLanguage ==
" ur "
;
}
In Visual Studio 2005, you have a new property TextInfo.IsRightToLeft that
indicates the direction of each culture. This is a simple code snippet to
detect the culture direction.
private static bool
CultureInfoIsRightToLeft()
{
return
System.Globalization.CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft;
}

Did you ever need to control the input language of your application
automatically, without the need for the user to switch the keyboard? This
functionality is not new in Visual Studio 2005, but it is interesting to
multilingual developers. You can easily set CurrentInputLanguage
of your application. In the following example I set the Input Language to the
CurrentCulture and in the second line I set it to Arabic ( Egypt ):
[C#]
InputLanguage.CurrentInputLanguage=
InputLanguage.FromCulture(
Application.CurrentCulture);
InputLanguage
.CurrentInputLanguage =
InputLanguage
.FromCulture(
new
CultureInfo(
"ar-eg"
));
The result of the first line is that the keyboard would be switched to the user
culture, while in the second case, the user would use the Arabic keyboard by
default. For more info check,
InputLanguage.CurrentInputLanguage Property (System.Windows.Forms)

There are numerous classes presented by GDI+ and GDI for rendering text on
Windows Forms. The GDI+ Graphics class has several DrawString methods that
allow you to specify various features of text, such as location, bounding
rectangle, font, and format. In addition, you can draw and measure text with
GDI using the static DrawText and MeasureText methods offered by the
TextRenderer class. The GDI methods also allow you to specify location, font,
and format.
In the case of RightToLeftLayout is true you should use GDI instead of GDI+.
This means, you need to use TextRenderer class to display text, while
RightToLeftLayout is true. On the other hand, if you use DrawString the text
would be mirrored and not readable. A better incentive to use GDI is that it
offers better performance and more accurate text measuring than GDI+.
With the introduction of RightToLeftLayout we need to examine two cases for text
display. The first is when RightToLeftLayout=true and the second is when
RightToLeftLayout=false.
Let's examine the first case, when RightToLeftLayout is set to
true:
You don't need to change the coordinates because the origin starts
from the rightmost edge instead of the left edge of the drawing area.
You don't need to set the rtl TextFormatFlags because they are set
by default.
The following code snippets show how to display text when RightToLeftLayout=true
and RightToLeft=yes:
[VB]
TextRenderer.DrawText(e.Graphics, " العربية !", Me.Font, New
Rectangle(5, 5, 50, 50), SystemColors.ControlText)
[C#]
TextRenderer.DrawText(e.Graphics, " العربية !", this.Font, new
Rectangle(5, 5, 50, 50), SystemColors.ControlText);
Let's examine the second case, when RightToLeftLayout is set to
false:
You need to calculate the correct left edge of your controls. Since
the origin is still on the left and not on the right.
You need to set the rtl TextFormatFlags because it
is not set by default. You need to specify TextFormatFlags.RightToLeft
.
The following code snippets show how to display text when
RightToLeftLayout=false and RightToLeft=yes:
[VB]
'We have to adjust the left of the drawing rectangle to draw the text in the
correct location
'NewLeft = FormWidth - (Left + Width)
TextRenderer.DrawText(e.Graphics, " العربية !", Me.Font, New
Rectangle(Me.Width - (5 + 50), 5, 50, 50),
SystemColors.ControlText, TextFormatFlags.RightToLeft)
[C#]
// We have to adjust the left of the drawing rectangle to draw the text in the
correct location
//NewLeft = FormWidth - (Left + Width)
TextRenderer.DrawText(e.Graphics, " العربية !", this.Font, new
Rectangle(this.Width - (5+50), 5, 50, 50),
SystemColors.ControlText, TextFormatFlags.RightToLeft);

Let's clarify some terminology before we discuss numbers and digits. In the
English language, the digits used: 0, 1, 2, ... 8, 9, are traditionally called
Arabic digits. The digits used in Arabic writing are traditionally called Indic
digits ( ٠١٢٣٤٥ ... ).
Indic digits are represented by the values U+0660 through U+0669 in Unicode.
However it is uncommon to store the Unicode values, we mostly store the Ansi
value of the digits and leave it to the OS to display the correct digits
according to the system settings. For instance, in Arabic text we would see
Indic digits at display only and not stored in Arabic. It was important to
store digits in a unified manner for several reasons. For example to perform
mathematical calculations and for sorting, etc…
For more information on how to set the digit substitution in Windows XP, check
this link
http://www.microsoft.com/middleeast/arabicdev/windows/winxp/DigitsSupport.aspx#digit
. This option exists in other versions of Windows too.
Windows Forms
The Windows default digit substitution is according to the context of the text.
This basically means, the digits will be displayed according to the context
they are at, in the middle of English text, 0,1,2 … In the middle of Arabic
text ٠ , ١ , ٢ , … .
However, most numbers are displayed alone without text, how would the system
decide on the digits to use?
In this case, the digits are based on the RightToLeft property.
This means, if RightToLeft =Yes then your digit substitution
will be Arabic and display Indic digits. Otherwise the digits are 0,1,2.
GDI+
In case you implement your own drawing, you need to specify how your digits
would appear in your DrawString. This is achieved using the
StringFormat.SetDigitSubstitution. For more info to this method please refer to
the
documentation . Below is a code snippet that shows how to display
digits using the different enums.
private void
IndicDigits_Paint(
object
sender,
PaintEventArgs
e)
{
StringFormat StrFormat =
new
StringFormat
();
int
AraLCID =
new
System.Globalization.
CultureInfo
(
"ar-eg"
).LCID;
StrFormat.SetDigitSubstitution(AraLCID,
StringDigitSubstitute
.National);
e.Graphics.DrawString( "Digit Substitution National 0,1,2,3,4,5,6,7,8,9" ,
this
.Font,
new
SolidBrush
(
this
.ForeColor),
new
PointF
(10, 10), StrFormat);
StrFormat.SetDigitSubstitution(AraLCID,
StringDigitSubstitute
.Traditional);
e.Graphics.DrawString(
"Digit Substitution Traditional 0,1,2,3,4,5,6,7,8,9"
,
this
.Font,
new
SolidBrush
(
this
.ForeColor),
new
PointF
(10, 30), StrFormat);
StrFormat.SetDigitSubstitution(AraLCID,
StringDigitSubstitute
.None);
e.Graphics.DrawString( "Digit Substitution None 0,1,2,3,4,5,6,7,8,9"
,
this
.Font,
new
SolidBrush (
this
.ForeColor),
new
PointF (10, 50), StrFormat);
StrFormat.SetDigitSubstitution(AraLCID,
StringDigitSubstitute
.User);
e.Graphics.DrawString( "Digit Substitution User 0,1,2,3,4,5,6,7,8,9"
,
this
.Font,
new
SolidBrush
(
this
.ForeColor),
new
PointF
(10, 70), StrFormat);
}

|