Blog from Saravanan Arumugam

Let us talk about Technologies

Monthly Archives: August 2010

Working with Cultures (Globalization)


Making a generic application that reach different people of different culture has always been a dream.
 
People in different regions not only use different language. The representation of Units, representation of Currency, representation of numbers, representation of Date time are all different. These representations are called cultures.
 
.Net presents a namespace that is dedicated to solve this need. System.Globalization.
 
Standard Representation of Culture Types
US english culture is represented by a string "en-US".
Here ‘en’ says the language, ‘US’ says the culture. ("language-Culture")
For example,
"en-GB" says English language with Great Britain culture
"ar-SA" says Arabic language with Saudi Arabian culture
"es-ES" says Spanish language with Spain culture.
There are something called Nutral Cultures where it takes only the language. ("en", "ar", "es")
Note: System.Globalization.CultureInfo class’s DisplayName property would help us understand these descriptions.
 
System.Globalization.CurrentInfo class
CurrentInfo class can be used to hold a culture specific information.  This call can be constructed with the Standard Culture reprentation ("language-Culture").
 
Knowing/Changing the current Culture
System.Threading.Thread.CurrentThread provides a static property CurrentCulture. This can be read or set by the application. This property takes System.Globalization.CultureInfo class (An example is presented below).
 
Formatting DateTime, Numbers and Currency
Though when we are talking about the different cultures, the application is going to be built on a single culture. But our interrest is on the Output/UI presentation.
 
While doing constructing an output, use the specific formatting to represent a specific culture information.
For example consider the following snippet.

info =

new CultureInfo("ru-RU");

sb.AppendLine((info).DisplayName);
sb.AppendLine(

"Russian Money: " + (1234567.89).ToString("C", info));

sb.AppendLine(

"Russian Date Time: " + DateTime.Now.ToString(info));

sb.AppendLine(

"Russian Numbers: " + (1234567.89).ToString(info));

In the line that prints "Russian Money: ", a floating point number is converted as currency string with Russian Culture info.

String.ToString(string format, IFormatProvider provider) overload is used here.

Note: CultureInfo has implementation of IFormatProvider.

 

The lines that print "Russian Date Time: ", "Russian Numbers: " are simply taking the ToString(IFormatProvider) overload to represent the date and numbers.

 

Customizing culture information

It is also possible to alter some of the culture specific informations. For example in the "es-GB" culture Date is represented as "dd/MM/yyyy". If we want to change the date separator, we can do so with the help of CultureInfo.DateTimeFormat.DateSeparator property.

There are a variety of methods and properties are provided within CultureInfo class to help customizing the culture information.

 

The following example illustrates various manupulations of CultureInfo class.

 

Note: I used a windows application’s MessageBox.Show() to represent these culture specific informations. Console application may not display some of the special characters in some cultures.

            StringBuilder sb = new StringBuilder();

            CultureInfo info = new CultureInfo("en-US");

            info.NumberFormat.CurrencySymbol = "Rs.";

            info.NumberFormat.CurrencyGroupSeparator = ":";

            info.DateTimeFormat.DateSeparator = "#";

            Thread.CurrentThread.CurrentCulture = info;

 

            sb.AppendLine(info.DisplayName);

            sb.AppendLine(info.DisplayName + " Money: " + (1234567.89).ToString("C"));

            sb.AppendLine(info.DisplayName + " Date Time: " + DateTime.Now);

            sb.AppendLine(info.DisplayName + " Numbers: " + 1234567.89);

 

            sb.AppendLine();

            info = new CultureInfo("es-ES");

            sb.AppendLine(info.DisplayName);

            sb.AppendLine(info.DisplayName + " Money: " +

(1234567.89).ToString("C", info));

            sb.AppendLine(info.DisplayName + " Date Time: " +

DateTime.Now.ToString(info));

            sb.AppendLine(info.DisplayName + " Numbers: " + (1234567.89).ToString(info));

 

            sb.AppendLine();

            info = new CultureInfo("it-IT");

            sb.AppendLine((info).DisplayName);

 

            sb.AppendLine(info.DisplayName + " Money: " +

(1234567.89).ToString("C", info));

            sb.AppendLine(info.DisplayName + " Date Time: " +

DateTime.Now.ToString(info));

            sb.AppendLine(info.DisplayName + " Numbers: " + (1234567.89).ToString(info));

 

            sb.AppendLine();

            info = new CultureInfo("ru-RU");

            sb.AppendLine((info).DisplayName);

            sb.AppendLine(info.DisplayName + " Money: " +

(1234567.89).ToString("C", info));

            sb.AppendLine(info.DisplayName + " Date Time: " +

DateTime.Now.ToString(info));

            sb.AppendLine(info.DisplayName + " Numbers: " + (1234567.89).ToString(info));

 

            sb.AppendLine();

            info = new CultureInfo("sma-NO");

            sb.AppendLine((info).DisplayName);

            sb.AppendLine(info.DisplayName + " Money: " +

(1234567.89).ToString("C", info));

            sb.AppendLine(info.DisplayName + " Date Time: " +

DateTime.Now.ToString(info));

            sb.AppendLine(info.DisplayName + " Numbers: " + (1234567.89).ToString(info));

 

            sb.AppendLine();

            info = new CultureInfo("ar-SA");

            sb.AppendLine((info).DisplayName);

            sb.AppendLine(info.DisplayName + " Money: " +

(1234567.89).ToString("C", info));

            sb.AppendLine(info.DisplayName + " Date Time: " +

DateTime.Now.ToString(info));

            sb.AppendLine(info.DisplayName + " Numbers: " + (1234567.89).ToString(info));

 

            sb.AppendLine();

            info = new CultureInfo("zh-MO");

            sb.AppendLine((info).DisplayName);

            sb.AppendLine(info.DisplayName + " Money: " +

(1234567.89).ToString("C", info));

            sb.AppendLine(info.DisplayName + " Date Time: " +

DateTime.Now.ToString(info));

            sb.AppendLine(info.DisplayName + " Numbers: " + (1234567.89).ToString(info));

 

            //foreach (CultureInfo inf in CultureInfo.GetCultures(CultureTypes.AllCultures))

            //    sb.AppendLine(inf.ToString());

            MessageBox.Show(sb.ToString());

 

The commented foreach loop, if uncommented, will display a list of all the supported Culture types.

Conventional Graphics Implementation in .Net framework 2.0


In today’s world, microsoft .Net support very enhanced UI implementations through WPF. Yet .Net framework 2.0 has given a lot of good classes that support standard graphics operations.
I had to go through the Graphics features provided in framework 2.0, since I am preparing for MCTS exam, Microsoft .Net Framework – Application Development Foundation.
 
I tried to do an animation that would create a standard 4 point polygan, and keep the vertices move so that a random polygon is shown all the time.
I have used a timer to draw the polygon in a picture box. Trigger and Clear buttons are used to Start and Stop the timer respectively. Timer’s Elapsed event calls the method that draws the polygon.
 
The windows application layout looks like this.
 
The code behind this is, (I find it difficult to format the code properly. So leave it with the default format that the site does.)

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.Drawing.Drawing2D;

 

namespace Graphics_Example

{

    public partial class Graphics_Animation : Form

    {

        System.Timers.Timer t;

        PolygonApex[] pa;

 

        public Graphics_Animation()

        {

            InitializeComponent();

        }

 

        private void Graphics_Animation_Load(object sender, EventArgs e)

        {

            t = new System.Timers.Timer();

            t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);

 

            pa = new PolygonApex[4];

            pa[0] = new PolygonApex(new Point(50, 1100), -1, 1,

                     GraphicsPictureBox.ClientRectangle);

            pa[1] = new PolygonApex(new Point(100, 1), -1, -1,

                     GraphicsPictureBox.ClientRectangle);

            pa[2] = new PolygonApex(new Point(120, 10), 1, 1,

                     GraphicsPictureBox.ClientRectangle);

            pa[3] = new PolygonApex(new Point(310, 75), 1, -1,

GraphicsPictureBox.ClientRectangle);

        }

 

        private void TriggerButton_Click(object sender, EventArgs e)

        {

            t.Interval = 10;

            t.Start();

        }

 

        void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)

        {

            DrawPolygon();

        }

 

        private void DrawPolygon()

        {

            Graphics g = GraphicsPictureBox.CreateGraphics();

            Brush b = new LinearGradientBrush(GraphicsPictureBox.ClientRectangle,

              Color.Green, Color.Orange, LinearGradientMode.ForwardDiagonal);

 

            Pen p = new Pen(b, 2);

 

            List<Point> points = new List<Point>();

 

            foreach (PolygonApex apex in pa)

            {

                apex.MovePoint();

                points.Add(apex.Point);

            }

            this.SuspendLayout();

            g.Clear(GraphicsPictureBox.BackColor);

            g.DrawPolygon(p, points.ToArray());

            this.ResumeLayout();

        }

 

        private class PolygonApex

        {

            public PolygonApex(Point p, int xDirection, int yDirection,

Rectangle boundary)

            {

                this.point = p;

                this.xDirection = xDirection;

                this.yDirection = yDirection;

                this.Boundary = boundary;

            }

 

            private Point point;

            public int xDirection { get; set; }

            public int yDirection { get; set; }

            public Rectangle Boundary { get; set; }

 

            public Point Point

            {

                get { return point; }

                set { point = value; }

            }

 

            public void MovePoint()

            {

                this.point.X += xDirection;

                if (this.point.X > Boundary.Right)

                {

                    this.point.X = Boundary.Right;

                    xDirection *= -1;

                }

                else if (this.point.X < Boundary.Left)

                {

                    this.point.X = Boundary.Left;

                    xDirection *= -1;

                }

 

                this.point.Y += yDirection;

                if (this.point.Y > Boundary.Bottom)

                {

                    this.point.Y = Boundary.Bottom;

                    yDirection *= -1;

                }

                else if (this.point.Y < Boundary.Top)

                {

                    this.point.Y = Boundary.Top;

                    yDirection *= -1;

                }

            }

        }

 

        private void ClearButton_Click(object sender, EventArgs e)

        {

            t.Stop();

            Graphics g = GraphicsPictureBox.CreateGraphics();

            g.Clear(GraphicsPictureBox.BackColor);

        }

 

        private void Graphics_Animation_Deactivate(object sender, EventArgs e)

        {

            t.Stop();

            Graphics g = GraphicsPictureBox.CreateGraphics();

            g.Clear(GraphicsPictureBox.BackColor);

        }

    }

}