Wednesday, November 21, 2007

Outlook Style Groupbox Control

Introduction
This article explains very simple implementation of a outlook style groupbox. This control also supports transparent background.


Features
Following are the customizable things in this control
  • Groupbox border color
  • Back image or icon

Transparent background

This is achieved by using follwing code.
bool _isTransparent = false;
[Browsable(true), Category("Appearance")]
public bool IsTransparent
{
get { return _isTransparent; }
set
{
_isTransparent = value;
if (_isTransparent == true)
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
}
Invalidate();
}
}

Source Code (Download here)

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace Owf.Controls
{
public partial class OutlookGroupBox : Panel
{
[Browsable(true)]
public new string Text
{
get { return base.Text; }
set
{
base.Text = value;
Invalidate();
}
}

private Color _lineColor = SystemColors.Highlight;
[Browsable(true), Category("Appearance")]
public Color LineColor
{
get { return _lineColor; }
set
{
_lineColor = value;
Invalidate();
}
}

private Image _image;
[Browsable(true), Category("Appearance")]
public Image Image
{
get { return _image; }
set
{
if (value != null)
{
_image = value;
_icon = null;
Invalidate();
}
}
}

private Icon _icon;
[Browsable(true), Category("Appearance")]
public Icon Icon
{
get { return _icon; }
set
{
if (value != null)
{
_icon = value;
_image = null;
Invalidate();
}
}
}

bool _isTransparent = false;
[Browsable(true), Category("Appearance")]
public bool IsTransparent
{
get { return _isTransparent; }
set
{
_isTransparent = value;
if (_isTransparent == true)
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
}
Invalidate();
}
}

public OutlookGroupBox()
{
InitializeComponent();
SetStyles();
}

public OutlookGroupBox(IContainer container)
{
container.Add(this);
InitializeComponent();
SetStyles();
}

void SetStyles()
{
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
}

private void OutlookGroupBox_Paint(object sender, PaintEventArgs e)
{
Font font = this.Font;
SizeF size = e.Graphics.MeasureString(this.Text, font);

e.Graphics.DrawString(this.Text, font, new SolidBrush(this.ForeColor), 1, 1);
e.Graphics.DrawLine(new Pen(_lineColor), size.Width + 3, (size.Height + 3) / 2,
this.Width - 5, (size.Height + 3) / 2);

if (_image != null)
{
e.Graphics.DrawImageUnscaled(_image, this.Padding.Left, this.Padding.Top);
}
else if (_icon != null)
{
e.Graphics.DrawIconUnstretched(_icon, new Rectangle(this.Padding.Left,
this.Padding.Top, _icon.Width, _icon.Height));
}
}
}
}

Tuesday, November 20, 2007

Test tốc độ trong .NET - System.Diagnostics.Stopwatch

System.Diagnostics.Stopwatch được sử dụng để xác định thời gian thực hiện một phương thức.

Lớp Stopwatch được xây dựng từ các API mức thấp. Nếu phần cứng và phiên bản Windows trên má tính hỗ trợ bộ đếm hiệu năng cao, nó sẽ sử dụng bộ đếm này thay cho đồng chuẩn của máy tính.

Đây là 1 ví dụ đơn giản:

System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();

watch.Start();

//do my stuff

...

watch.Stop();

MessageBox.Show("Time spent: " + watch.Elapsed.ToString());

?? operator (C#)

Toán tử ?? trả lại toán hạng bên trái nếu toán hạng này khác null, trả về giá trị bên phải trong trường hợp còn lại. Ví dụ:

int? x = null;

...

// y = x, nếu x khác null, khi x = null, y = -1.

int y = x ?? -1;

Toán tử ?? cũng làm việc với kiểu tham chiếu:

//message = param, nếu param khác null

//trong trường hợp param = null, message = "No message"

string message = param ?? "No message";

How to perform DateTime calculations in a right way

When coding, be careful if you need to perform DateTime calculations (add/subtract) on values representing time zones that practice daylight savings time. Unexpected calculation errors can result. Instead, convert the local time value to universal time, perform the calculation, and convert back to achieve maximum accuracy.

DateTime d;

d = DateTime.Parse("Oct 26, 2003 12:00:00 AM"); //date assignment

d = d.ToUniversalTime().AddHours(3.0).ToLocalTime();

//' - displays 10/26/2003 02:00:00 AM – Correct!

MessageBox.Show(d.ToString());

Working with DateTime structs seems to be simple, but it's not. Make sure you are aware of pitfalls discribed in the article Coding Best Practices Using DateTime in the .NET Framework.

Wednesday, August 22, 2007

Echo2 - Một nền tảng AJAX cho Java

Echo2 hợp nhất công nghệ AJAX với framework server-side thực tế để tạo ra một nền tảng ứng dụng web phiên bản tiếp theo, Echo2 cung cấp một framework quen thuộc và hướng đối tượng mạnh mẽ mà tăng cường khả năng thiết kế hướng sự kiện cho các bộ dụng cụ giao diện người dùng thick-client truyền thống như Java Swing hoặc Eclipse SWT. Echo2 tăng cường khả năng của kỹ thuật AJAX để tạo ra các ứng dụng Internet đẹp bằng cách sử dụng kinh nghiệm được sử dụng để tạo ra các ứng dụng trên desktop.

Các tính năng của Echo2:

  • Các ứng dụng được phát triển bằng Java dạng server-side sử dụng một API hướng thành phàn và điều khiển sự kiện mà làm việc như một bộ công cụ giao diện người sử dụng.
  • Việc tạo ra giao diện được thực hiện hoàn toàn thông qua AJAX, sử dụng một tài liệu HTML đơn giản. Việc cập nhật từ server được thực hiện trong một vùng nhỏ nhất có thể được, chỉ cập nhật các vị trí trên tài liệu HTML đã thay đổi.
  • Các ứng dụng có thể hiển thị các dialog dạng modal, nơi mà ứng dụng sẽ không cho phép nhập dữ liệu bên ngoài vùng được xác định.
  • Kỹ thuật Server push cho phép một ứng dụng điều khiển các trình duyệt của client mà không theo vòng lặp yêu cầu/đáp ứng web truyền thống.
  • Một API phát triển dạng thành phần mở rộng cho phép việc tạo ra các thành phần AJAX tái sử dụng.
  • Các trình duyệt được hỗ trợ bao gồm Firefox, Internet Explorer, Opera, Konqueror, Safari, Mozilla, và Netscape.

Tuesday, August 21, 2007

Groovy - Một ngôn ngữ động linh động cho Java Platform

Groovy ...
  • is an agile and dynamic language for the Java Virtual Machine
  • builds upon the strengths of Java but has additional power features inspired by languages like Python, Ruby and Smalltalk
  • makes modern programming features available to Java developers with almost-zero learning curve
  • supports Domain Specific Languages and other compact syntax so your code becomes easy to read and maintain
  • makes writing shell and build scripts easy with its powerful processing primitives, OO abilities and an Ant DSL
  • increases developer productivity by reducing scaffolding code when developing web, GUI, database or console applications
  • simplifies testing by supporting unit testing and mocking out-of-the-box
  • seamlessly integrates with all existing Java objects and libraries
  • compiles straight to Java bytecode so you can use it anywhere you can use Java

Friday, August 17, 2007

Automatically send keys to other application

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace ConsoleApplicationTest
{
   class Program
   {
       [System.Runtime.InteropServices.DllImport("USER32.DLL", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
       static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
       [System.Runtime.InteropServices.DllImport("USER32.DLL", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
       static extern bool SetForegroundWindow(IntPtr hWnd);

       static void Main(string[] args)
       {
           Process calc = Process.Start("calc.exe");
           calc.WaitForInputIdle();

           IntPtr calculatorHandle = FindWindow(null, "Calculator");
           if (calculatorHandle == IntPtr.Zero)
           {
               Console.WriteLine("Calculator is not running.");
           }
           else
           {
               SetForegroundWindow(calculatorHandle);
               SendKeys.SendWait("13");
               SendKeys.SendWait("*");
               SendKeys.SendWait("13");
               SendKeys.SendWait("=");
           }
       }
   }
} 

Thursday, August 16, 2007

Những điểm mới trong CSharp 3.0

Sau đây tóm tắt những điểm chính của các tính năng được giới thiệu trong C# 3.0

Khai báo biến địa phương sử dụng kiểu 'var'

  • Các biến địa phương có thể được khai báo bằng kiểu 'var', khi đó trình biên dịch sẽ xác định kiểu được sử dụng dựa trên dữ liệu được khởi tạo.
var i = 10; // i được tạo ra với kiểu int var name = “MyName” ; // name được tạo ra có kiểu string
  • Chỉ có thể được sử dụng khi được khai báo và khởi tạo trong cùng một câu lệnh.
  • Không được khởi tạo giá trị null.
  • Không được sử dụng trong các trường dữ liệu của lớp.
  • Hầu hết được sử dụng để lưu các kiểu không xác định trong việc lập trình dựa trên LINQ.

Khởi tạo đối tượng và tập hợp

  • Cho phép xác định giá trị vào bất kỳ trường dữ liệu hoặc thuộc tính của một kiểu dữ liệu tại thời điểm khởi tạo mà không cần triệu gọi phương thức khởi tạo (constructor) với các tham số.
  • Phương thức constructor ngầm định được thực hiện trước khi xác định giá trị.
Ví dụ: Coordinate c1 = new Coordinate {x=1 , y=2};
  • Được sử dụng trong các biểu thức truy vấn của LINQ cùng với các kiểu không xác định.
  • Hàm khởi tạo tập hợp (collection) sử dụng hàm khởi tạo đối tượng để xác định các giá trị thành phần của tập hợp mà không cần gọi phương thức Add nhiều lần.

Các phương thức mở rộng

  • Cho phép thêm phương thức mới vào kiểu hiện có mà không phải thay đổi kiểu dữ liệu đó.
  • Là các phương thức tĩnh đặc biệt nhưng được gọi như là các phương thức của instance.
  • Tham số đầu tiên được truyền vào các phương thức mở rộng xác định kiểu mà chúng thao tác được xử lý bởi từ khóa 'this'.
  • Chúng không thể truy cập các biến riêng (private) của kiểu dữ liệu mà chúng được mở rộng.
  • Các phương thức mở rộng cần được định nghĩa trong lớp tĩnh dạng non-nested và non-generic.
  • Các phương thức của instance được ưu tiên hơn so với các phương thức mở rộng trong trường hợp chúng có cùng tên (signature).

Kiểu không xác định

  • Are of class types which can have only public read-only properties as their members. No other class members like methods are allowed.
  • They are of reference types and are derived from ‘Object’ class.
  • Internally compiler gives them the name but its not accessible by application code.
  • They have a method scope.
  • Can be initiated directly e.g. new { property1=1, property2=”Hello World”};

Lambda Expressions

  • Very similar to anonymous methods introduced in C# 2.0.
  • Its an inline expression or statement block which can be used to pass arguments to method call or assign value to delegate.
  • All lambda expression use lambda operator => where the left side denotes result and right contains statement block or expression.

Auto-Implemented Properties

  • Helps in simplifying property declaration in cases where there is no custom logic required in accessors methods.
  • E.g. public int Price {get; set;};
  • Internally compiler creates an anonymous field for assigning values.

In my next post on this i will demonstrate these using a code sample.

Tuesday, August 14, 2007

CSharp Tip #1 : Static Classes

In .NET Framework 1.x, Static Classes are created by defining a class with a private constructor with one or more static members so that instance of the class cannot be created using new operator.

In .NET Framework 2.0 the need for such a private constructor is avoided by using a static keyword along with the class definition. Static classes are sealed and therefore cannot be inherited. Static classes cannot contain a constructor, although it is still possible to declare a static constructor to assign initial values.

using System;
using System.Collections.Generic;
using System.Text;

namespace VikasGoyal.StaticClasses
{
  class Program
  {
      static void Main(string[] args)
      {
          Console.WriteLine(StaticClass.getName());
          Console.WriteLine(StaticClass.getName());
          Console.WriteLine(StaticClass.getName());
      }
  }
  static class StaticClass
  {
      private static string name;
      static StaticClass()
      {
          name = "Vikas Goyal";
          Console.WriteLine("In Constructor");
      }
      public static string getName()
      {
          return name;
      }
  }
}
OUTPUT
In Constructor
Vikas Goyal
Vikas Goyal
Vikas Goyal

Cách xóa bất kỳ file nào trong Windows

Đây là phần mềm miễn phí tiện dụng cho phép xóa bất kỳ file nào mà Windows đang chạy.

Thường thì bạn sẽ nhận được một trong các thông báo sau nếu file bị khóa:

Cannot Delete file: Access is denied.

There has been a sharing vilation.

The source or destination file may be in use.

The files is in use by another program of user.

Make sure the disk is not full or write-protected and that the file is not currently in use.

Unlocker sẽ làm mọi thứ đơn giản hơn. Sau khi cài đặt chương trình, bạn sẽ thấy lựa chọn Unlocker xuất hiện ngay khi nhấp chuột vào bất kỳ file hay folder nào trong Windows Explorer. Để mở khóa cho file, bạn nhấn chuột phải vào đó > chọn Unlocker. Chọn Unlock all rồi đóng phần mềm này lại. Lúc này, bạn có thể xóa thoải mái trong Windows Explorer. Địa chỉ tải chương trình: http://ccollomb.free.fr/unlocker/

Monday, July 23, 2007

How to Perform SQL Server Row-by-Row Operations Without Cursors

SQL cursors have been a curse to database programming for many years because of their poor performance. On the other hand, they are extremely useful because of their flexibility in allowing very detailed data manipulations at the row level. Using cursors against SQL Server tables can often be avoided by employing other methods, such as using derived tables, set-based queries, and temp tables. A discussion of all these methods is beyond the scope of this article, and there are already many well-written articles discussing these techniques.

The focus of this article is directed at using non-cursor-based techniques for situations in which row-by-row operations are the only, or the best method available, to solve a problem. Here, I will demonstrate a few programming methods that provide a majority of the cursor’s flexibility, but without the dramatic performance hit.

Let’s begin by reviewing a simple cursor procedure that loops through a table. Then we’ll examine a non-cursor procedure that performs the same task.

In this example, i use a table:

tblCustomers

{

CustomerNo varchar (10) (PK),

CustomerName nvarchar(50)

}

With using cursor for loops through the table tblCustomers:

-- declare all variables!

DECLARE @CustomerNo varchar(10),

@CustomerName nvarchar(50)

-- declare the cursor

DECLARE Customer_Cursor CURSOR FOR

SELECT CustomerNo,

CustomerName

FROM tblCustomers

OPEN Customer_Cursor

FETCH Customer_Cursor INTO @CustomerNo, @CustomerName

-- start the main processing loop.

WHILE @@FETCH_STATUS = 0

BEGIN

-- This is where you perform your detailed row-by-row

-- processing.

-- Example:

PRINT 'Customer No: ' + @CustomerNo + '; Customer Name: ' + @CustomerName

-- Get the next row.

FETCH Customer_Cursor INTO @CustomerNo, @CustomerName

END

CLOSE Customer_Cursor

DEALLOCATE Customer_Cursor

As you can see, this is a very straight-forward cursor procedure that loops through a table called tblCustomers and retrieves CustomerNo and CustomerNumber for every row. Now we will examine a non-cursor version that does the exact same thing:

-- declare all variables!

DECLARE @CustomerNo varchar(10),

@CustomerName nvarchar(50)

DECLARE @RowCount int DECLARE @RowIndex int

SELECT @RowCount = COUNT(CustomerNo) FROM tblCustomers

SET @RowIndex = 1 IF (@RowCount > 0)

BEGIN

WHILE (@RowIndex <= @RowCount) BEGIN SET ROWCOUNT @RowIndex SELECT @CustomerNo = CustomerNo, @CustomerName = CustomerName FROM tblCustomers SET @RowIndex = @RowIndex + 1 -- This is where you perform your detailed row-by-row

-- processing.

-- Example:

PRINT 'Customer No: ' + @CustomerNo + '; Customer Name: ' + @CustomerName END--end while

END

Friday, June 29, 2007

How To Resize A SQL Server Transaction Log

This is sample for resize a SQL Server transaction log.

USE AdventureWorks;
GO
-- Truncate the log by changing the database recovery model to SIMPLE.
    ALTER DATABASE AdventureWorks
    SET RECOVERY SIMPLE;
    GO
    
    -- Shrink the truncated log file to 1 MB.
    DBCC SHRINKFILE (AdventureWorks_Log, 1);
    GO

    -- Reset the database recovery model.
    ALTER DATABASE AdventureWorks
    SET RECOVERY FULL;
    GO

Thursday, June 28, 2007

Hàm đọc số thành chuỗi

Ưu điểm: + Đọc được tới số 79.228.162.514.264.337.593.543.950.335 (bảy mươi chín tỉ tỉ tỉ hai trăm hai mươi tám triệu tỉ tỉ một trăm sáu mươi hai ngàn tỉ tỉ năm trăm mười bốn tỉ tỉ hai trăm sáu mươi bốn triệu tỉ ba trăm bốn mươi ngàn tỉ sáu trăm tám mươi mốt tỉ năm trăm bốn mươi lăm triệu bảy trăm bốn mươi bốn ngàn ba trăm tám mươi bốn) + Hỗ trợ các luật phát âm lẩm cẩm: một/mốt, mươi/mười, năm/lăm/nhăm + Cho thay đổi các cách phát âm: linh/lẻ, nghìn/ngàn, vv... Nhược điểm: + Không hỗ trợ số thập phân (vì dùng lại class này 2 lần sẽ đạt được tính năng đó) + Đối với số cực lớn, đôi lúc đọc lệch đi 1 tí xíu (vì bản chất là dựa trên kiểu double, mà bản thân double có precision không cao như decimal) Mã nguồn C#: (Các fan VB.NET chịu khó tìm converter để convert đi nhá, có đầy trên mạng rồi. Với lại tui ko thích chơi với VB) Big Smile [:D] #region Using directives using System; using System.Text; #endregion namespace Thn.Application.Utilities { /// <summary> /// Converts from a number to words. (Vietnamese rule) /// Author : Nguyễn Minh Hải /// Rev : Aug 21, 2006 /// Features : /// + number can be as big/small as a decimal can support /// + does not support decimal points (he he, YOU should implement that) /// Copyright: /// + use it anyway you like, as long as you retain credits to original author /// </summary> public class NumberToText { #region Names /// <summary> /// name of simple number digit /// </summary> protected string[] mDigits = new string[] { "không", "một", "hai", "ba", "bốn", "năm", "sáu", "bảy", "tám", "chín", "mười" }; /// <summary> /// Name of digit groups /// </summary> protected string[] mGroups = new string[] {"trăm", "ngàn", "triệu", "tỉ", "ngàn tỉ", "triệu tỉ", "tỉ tỉ", "ngàn tỉ tỉ", "triệu tỉ tỉ", "tỉ tỉ tỉ" }; /// <summary> /// name of single sequence digit (linh, lẻ) /// </summary> protected string mZeroSequence = "lẻ"; /// <summary> /// alternative name of One /// </summary> protected string mAltOne = "mốt"; /// <summary> /// alternative name of Five /// </summary> protected string mAltFive = "lăm"; /// <summary> /// postfix for tens /// </summary> protected string mTenPostfix = "mươi"; /// <summary> /// name of negative sign /// </summary> protected string mNegative = "trừ"; #region Unit Name private string mUnitName = "đồng"; /// <summary> /// Gets/Sets name of unit /// </summary> public string UnitName { get { return mUnitName; } set { mUnitName = value; } } #endregion #endregion #region Build group bool useZeroHundred = false; /// <summary> /// Build name of a group (expected value: [0, 999] /// </summary> protected virtual string BuildGroup(int value) { StringBuilder result = new StringBuilder(); bool useAlt = false; bool zeroTen = false; bool zeroHundred = false; //build hundred int digit = value / 100; if (useZeroHundred || (digit != 0)) { result.Append(mDigits[digit] + " " + mGroups[0]); } zeroHundred = digit == 0; //build ten digit = value % 100 / 10; if (digit == 0) zeroTen = true; else { if (digit == 1) result.Append(" " + mDigits[10]); else result.Append(" " + mDigits[digit] + " " + mTenPostfix); } useAlt = (digit != 0) && (digit != 1); //build unit digit = value % 10; if ((digit!=0)&& zeroTen) { if (zeroHundred) { if (useZeroHundred) result.Append(" " + mZeroSequence + " " + mDigits[digit]); else result.Append(" " + mDigits[digit]); } else { result.Append(" " + mZeroSequence + " " + mDigits[digit]); } } else if (digit == 1) { if (useAlt) result.Append(" " + mAltOne); else result.Append(" " + mDigits[1]); } else if (digit == 5) { if (zeroTen) result.Append(" " + mDigits[5]); else result.Append(" " + mAltFive); } else if (digit != 0) result.Append(" " + mDigits[digit]); return result.ToString(); } #endregion #region Get Group Name /// <summary> /// Build group's name based on the power of group /// </summary> string GetGroupName(int power) { string result = ""; int idx = power / 3; if ((idx > 0) && (idx < mGroups.Length)) result = mGroups[idx]; //else if (idx > 0) result = GetGroupName(idx) + " " + mGroups[3]; return result; } #endregion #region Parse /// <summary> /// Converts a number to words /// </summary> public virtual string Parse(double value) { string result = ""; StringBuilder sb = new StringBuilder(); if (value == 0) result = mDigits[0] + " " + mUnitName; else { if (value < 0) { result = mNegative + " "; value = -value; } int length = (int)Math.Log10((double)value); int group = 0; useZeroHundred = false; while (length >= 0) { int groupLength = length; while (groupLength % 3 != 0) groupLength--; group = (int)(value / Math.Pow(10, groupLength)); if (group > 0) { sb.Append(BuildGroup(group)); sb.Append(" " + GetGroupName(length) + " "); } string tmp = sb.ToString(); //prepare for next group value = value - group * Math.Pow(10, groupLength); length -= 3; useZeroHundred = true; }//while length > 0 result += sb.ToString().Trim() + " " + mUnitName; } return result; } /// <summary> /// Converts a number to words /// </summary> public virtual string Parse(decimal value) { return Parse((double)value); } /// <summary> /// Converts a number to words /// </summary> public virtual string Parse(int value) { return Parse(value); } #endregion #region Constructors /// <summary> /// Default constructor /// </summary> public NumberToText() { } #endregion } } Danh sách các số đã kiểm chứng: 0 - không đồng 1 - một đồng 2 - hai đồng 3 - ba đồng 4 - bốn đồng 5 - năm đồng 6 - sáu đồng 7 - bảy đồng 8 - tám đồng 9 - chín đồng 10 - mười đồng 11 - mười một đồng 15 - mười lăm đồng 12 - mười hai đồng 20 - hai mươi đồng 21 - hai mươi mốt đồng 22 - hai mươi hai đồng 25 - hai mươi lăm đồng 99 - chín mươi chín đồng -99 - trừ chín mươi chín đồng 100 - một trăm đồng 101 - một trăm lẻ một đồng 102 - một trăm lẻ hai đồng 105 - một trăm lẻ năm đồng 110 - một trăm mười đồng 111 - một trăm mười một đồng 112 - một trăm mười hai đồng 115 - một trăm mười lăm đồng 201 - hai trăm lẻ một đồng 202 - hai trăm lẻ hai đồng 205 - hai trăm lẻ năm đồng 210 - hai trăm mười đồng 211 - hai trăm mười một đồng 212 - hai trăm mười hai đồng 215 - hai trăm mười lăm đồng 220 - hai trăm hai mươi đồng 221 - hai trăm hai mươi mốt đồng 222 - hai trăm hai mươi hai đồng 225 - hai trăm hai mươi lăm đồng 500 - năm trăm đồng 505 - năm trăm lẻ năm đồng 550 - năm trăm năm mươi đồng 555 - năm trăm năm mươi lăm đồng 995 - chín trăm chín mươi lăm đồng 999 - chín trăm chín mươi chín đồng 1.000 - một ngàn đồng 1.001 - một ngàn không trăm lẻ một đồng 1.005 - một ngàn không trăm lẻ năm đồng 1.009 - một ngàn không trăm lẻ chín đồng 1.010 - một ngàn không trăm mười đồng 1.011 - một ngàn không trăm mười một đồng 1.012 - một ngàn không trăm mười hai đồng 1.015 - một ngàn không trăm mười lăm đồng 1.020 - một ngàn không trăm hai mươi đồng 1.021 - một ngàn không trăm hai mươi mốt đồng 1.022 - một ngàn không trăm hai mươi hai đồng 1.025 - một ngàn không trăm hai mươi lăm đồng 1.100 - một ngàn một trăm đồng 1.101 - một ngàn một trăm lẻ một đồng 1.102 - một ngàn một trăm lẻ hai đồng 1.105 - một ngàn một trăm lẻ năm đồng 1.110 - một ngàn một trăm mười đồng 1.111 - một ngàn một trăm mười một đồng 1.115 - một ngàn một trăm mười lăm đồng 1.200 - một ngàn hai trăm đồng 1.201 - một ngàn hai trăm lẻ một đồng 1.205 - một ngàn hai trăm lẻ năm đồng 1.210 - một ngàn hai trăm mười đồng 1.211 - một ngàn hai trăm mười một đồng 1.215 - một ngàn hai trăm mười lăm đồng 1.500 - một ngàn năm trăm đồng 1.505 - một ngàn năm trăm lẻ năm đồng 1.550 - một ngàn năm trăm năm mươi đồng 1.555 - một ngàn năm trăm năm mươi lăm đồng 1.000.000 - một triệu đồng 1.000.001 - một triệu không trăm lẻ một đồng 1.000.002 - một triệu không trăm lẻ hai đồng 1.000.010 - một triệu không trăm mười đồng 1.000.011 - một triệu không trăm mười một đồng 1.000.100 - một triệu một trăm đồng 1.000.101 - một triệu một trăm lẻ một đồng 1.001.000 - một triệu không trăm lẻ một ngàn đồng 1.001.001 - một triệu không trăm lẻ một ngàn không trăm lẻ một đồng 1.010.000 - một triệu không trăm mười ngàn đồng 1.011.000 - một triệu không trăm mười một ngàn đồng 1.011.001 - một triệu không trăm mười một ngàn không trăm lẻ một đồng 1.100.000 - một triệu một trăm ngàn đồng 1.110.000 - một triệu một trăm mười ngàn đồng 1.200.000 - một triệu hai trăm ngàn đồng 1.210.000 - một triệu hai trăm mười ngàn đồng 10.000.000 - mười triệu đồng 11.000.000 - mười một triệu đồng 100.000.000 - một trăm triệu đồng 200.000.000 - hai trăm triệu đồng 1.000.000.000 - một tỉ đồng 10.000.000.000 - mười tỉ đồng 100.000.000.000 - một trăm tỉ đồng 1.000.000.000.000 - một ngàn tỉ đồng 10.000.000.000.000 - mười ngàn tỉ đồng 100.000.000.000.000 - một trăm ngàn tỉ đồng 1.000.000.000.000.000 - một triệu tỉ đồng 10.000.000.000.000.000 - mười triệu tỉ đồng 100.000.000.000.000.000 - một trăm triệu tỉ đồng 1.000.000.000.000.000.000 - một tỉ tỉ đồng 10.000.000.000.000.000.000 - mười tỉ tỉ đồng 100.000.000.000.000.000.000 - một trăm tỉ tỉ đồng 1.000.000.000.000.000.000.000 - một ngàn tỉ tỉ đồng 10.000.000.000.000.000.000.000 - mười ngàn tỉ tỉ đồng 100.000.000.000.000.000.000.000 - chín mươi chín ngàn tỉ tỉ chín trăm chín mươi chín tỉ tỉ chín trăm chín mươi chín triệu tỉ chín trăm chín mươi chín ngàn tỉ chín trăm chín mươi chín tỉ chín trăm tám mươi chín triệu năm trăm mười bốn ngàn hai trăm bốn mươi đồng 1.000.000.000.000.000.000.000.000 - một triệu tỉ tỉ đồng 10.000.000.000.000.000.000.000.000 - mười triệu tỉ tỉ không trăm lẻ hai tỉ một trăm bốn mươi bảy triệu bốn trăm tám mươi ba ngàn sáu trăm bốn mươi tám đồng 100.000.000.000.000.000.000.000.000 - một trăm triệu tỉ tỉ đồng 1.000.000.000.000.000.000.000.000.000 - một tỉ tỉ tỉ đồng 10.000.000.000.000.000.000.000.000.000 - mười tỉ tỉ tỉ đồng 79.228.162.514.264.337.593.543.950.335 - bảy mươi chín tỉ tỉ tỉ hai trăm hai mươi tám triệu tỉ tỉ một trăm sáu mươi hai ngàn tỉ tỉ năm trăm mười bốn tỉ tỉ hai trăm sáu mươi bốn triệu tỉ ba trăm bốn mươi ngàn tỉ sáu trăm tám mươi mốt tỉ năm trăm bốn mươi lăm triệu bảy trăm bốn mươi bốn ngàn ba trăm tám mươi bốn đồng Viết bằng ngôn ngữ VB.NET Option Explicit On Imports System.Text Public Class ReadNumVNUnicode '********************************^^^^^^^************************************* ' All things I've done here is for education and research purposes only!!! ' Mail: classical_boy1988@yahoo.com '**************************************************************************** #Region "First Declare & Global Variants..." Public Event NotNumeric(ByVal strWrongNum As String) ' biến cố dùng cho ng</FONT><FONT size=2>ýời dùng nếu không phải là số... 'Các biến lýu giữ tính chất... Dim mReadZero As String = "lẻ" Dim mReadDecimal As String = "phẩy" Dim mReadNegative As String = "trừ" Dim mReadThousand As String = "ngh</FONT><FONT size=2>ìn" Dim mReadDigit5 As String = "l</FONT><FONT size=2>ăm" ' Private Variants... Dim strDecimal As String 'biến to</FONT><FONT size=2>àn cục, chứa thông tin về dấu chấm thập phân Dim strThousand As String 'biến toàn cục, chứa thông tin về dấu phân cách hàng ngàn Dim iDecimal As Int32 ' biến toàn cục, giữ vị trí của dấu phẩy trong số </FONT><FONT size=2>được đọc. Dim bNegative As Boolean ' số được đọc âm hay dương? 'Các mảng lưu cách đọc... Dim arrHangDV() As String = {"", "mốt ", "hai ", "ba ", _ "bốn ", "lăm ", "sáu ", "bảy ", "tám ", "chín "} Dim arrHangDV0() As String = {"không ", "một ", "hai ", "ba ", _ "bốn ", "năm ", "sáu ", "bảy ", "tám ", "chín "} Dim arrHangDV1() As String = {"", "một ", "hai ", "ba ", _ "bốn ", "lăm ", "sáu ", "bảy ", "tám ", "chín "} Dim arrHangChuc() As String = {"lẻ ", "mười ", "hai mươi ", "ba mươi ", _ "bốn mươi ", "năm mươi ", "sáu mươi ", "bảy mươi ", "tám mươi ", "chín mươi "} Dim arrHangTram() As String = {"không trăm ", "một trăm ", "hai trăm ", "ba trăm ", _ "bốn trăm ", "năm trăm ", "sáu trăm ", "bảy trăm ", "tám trăm ", "chín trăm "} #End Region #Region "Properties " Public Property ReadThousand() As String 'Cách đọc h</FONT><FONT size=2>àng nghìn, vdụ: nghìn, ngàn... Mặc </FONT><FONT size=2>định l</FONT><FONT size=2>à "nghìn" Get Return mReadThousand End Get Set(ByVal value As String) mReadZero = value End Set End Property Public Property ReadDigit5() As String 'Cách đọc số 5, vdụ: lăm, nhăm...(hai mươi lăm, hai mươi nhăm). Mặc định là "lăm" 'Lưu ý: 105 đọc là "một trăm lẻ năm", ko thể đọc là "một trăm lẻ nhăm" hay "một trăm lẻ lăm" Get Return mReadDigit5 End Get Set(ByVal value As String) mReadDigit5 = value arrHangDV(5) = mReadDigit5 & Chr(32) arrHangDV1(5) = mReadDigit5 & Chr(32) End Set End Property Public Property ReadZero() As String 'Cách đọc số không (0) ở hàng chục, vdụ: lẻ, linh... Mặc định là "lẻ" Get Return mReadZero End Get Set(ByVal value As String) mReadZero = value arrHangChuc(0) = Trim(mReadZero) & Chr(32) End Set End Property Public Property ReadNegative() As String 'Cách đọc dấu trừ nếu là số âm, vdụ: trừ, âm... Mặc </FONT><FONT size=2>định l</FONT><FONT size=2>à "trừ" Get Return mReadNegative End Get Set(ByVal value As String) mReadNegative = value End Set End Property Public Property ReadDecimal() As String 'Cách </FONT><FONT size=2>đọc dấu chấm thập phân, vdụ: phết, phẩy... Mặc định l</FONT><FONT size=2>à "phẩy" Get Return mReadDecimal End Get Set(ByVal value As String) mReadDecimal = value End Set End Property Public ReadOnly Property DecimalSymbol() As String 'Cho biết kí hiệu dùng </FONT><FONT size=2>để biểu diễn dấu chấm thập phân cảu hệ thống Get DecimalSymbol = strDecimal End Get End Property Public ReadOnly Property DigitGroupSymbol() As String 'Kí hiệu d</FONT><FONT size=2>ùng </FONT><FONT size=2>để biểu diễn dấu phân cách h</FONT><FONT size=2>àng ngàn của hệ thống... Get DigitGroupSymbol = strThousand End Get End Property #End Region #Region "Private Subs " Private Function GetDicemal(ByRef a As Byte) As String ' lấy thông tin về dấu chấm thập phân & dấu phân cách hàng ngàn Dim regKey As Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Control PanelInternational") If a = 0 Then ' lấy thông tin về dấu chấm thập phân GetDicemal = regKey.GetValue("sDecimal", ",").ToString Else 'lấy thông tin về dấu phân cách hàng ngàn GetDicemal = regKey.GetValue("sThousand", ".").ToString End If regKey = Nothing End Function Private Function Read3Digits(ByVal str3Digits As String, ByRef k As Int32) As String Dim sRead As String = "" Dim iDV, iChuc, iTram As Int32 If str3Digits = "000" Then Return vbNullString iDV = CInt(Right(str3Digits, 1)) If str3Digits.Length > 1 Then iChuc = CInt(Mid(str3Digits, str3Digits.Length - 1, 1)) iTram = IIf(str3Digits.Length = 3, CInt(Left(str3Digits, 1)), 0) If str3Digits.Length = 1 Then sRead = arrHangDV0(iDV) If str3Digits.Length = 2 Then sRead = arrHangChuc(iChuc) & Choose(IIf(iChuc > 1, 3, iChuc + 1), _ arrHangDV0(iDV), arrHangDV1(iDV), arrHangDV(iDV)) If str3Digits.Length = 3 Then sRead = arrHangTram(iTram) & IIf(iChuc + iDV <> 0, _ Read3Digits(iChuc.ToString & iDV.ToString, 1), "") 'Trên thực tế, bạn có thể thay arrHangTram(iTram) bằng arrHangDV0(iTram) & "tr</FONT><FONT size=2>ăm " sRead = sRead & Choose(k Mod 3 + 1, "triệu ", "", mReadThousand & Chr(32)) & _ Space((k - 1) 3).Replace(Chr(32), "tỉ ") Return sRead End Function Private Function CheckNum(ByRef sNumToCheck As String) As String 'H</FONT><FONT size=2>àm kiểm tra lại số mà ng</FONT><FONT size=2>ýời dùng nhập Dim i As Int32 = 1, num As String = sNumToCheck Do While i <= num.Length Select Case Asc(Mid(num, i, 1)) Case Asc("0") To Asc("9") ' không làm g</FONT><FONT size=2>ì cả!!! Case Asc(Trim(strDecimal)) If iDecimal <> 0 Then GoTo NotNum Else If i = 1 Then num = "0" & num iDecimal = i End If Case Asc("-") If bNegative Or i <> 1 Then GoTo NotNum Else bNegative = True End If Case Else NotNum: num = Left(num, i - 1) & Right(num, Len(num) - i) i = i - 1 End Select i = i + 1 Loop If Not (IsNumeric(num)) Then RaiseEvent NotNumeric(sNumToCheck) Return vbNullString Else If num.Replace("0", "") = "" Then num = "0" Else i = 0 Do While i < num.Length If Left(num, 1) = "0" Then num = Mid(num, 2) Else Exit Do End If i += 1 Loop End If 'Return FormatNumber(num, IIf(iDecimal <> 0, num.Length - iDecimal, 0), TriState.True, TriState.False, TriState.False) Return num End If End Function #End Region Public Function Read(ByVal Number As String) As StringBuilder Dim i, iStart, iLen As Int32 Dim sNum As String, sRead As New StringBuilder("") sNum = Number sNum = CheckNum(Number) If Trim(sNum) = vbNullString Then Return sRead If bNegative Then ' nếu là số âm sRead.Append(mReadNegative & Chr(32)) sNum = Mid(sNum, 2) : bNegative = False End If If iDecimal <> 0 Then ' nếu là số thập phân iStart = iDecimal - IIf(sRead.Length <> 0, 1, 0) 'Giải thích: sRead.Length <> 0 nghĩa là </FONT><FONT size=2>đ</FONT><FONT size=2>ã </FONT><FONT size=2>đọc mReadNegative v</FONT><FONT size=2>ào rồi (số âm) iDecimal = 0 sRead.Append(Read(Left(sNum, iStart - 1)).ToString & mReadDecimal & _ Chr(32) & Read(Mid(sNum, iStart + 1)).ToString) Else 'nếu là số nguyên (ko chấm thập phân) iStart = 1 iLen = IIf(sNum.Length Mod 3 = 0, 3, sNum.Length - 3 * (sNum.Length 3)) For i = sNum.Length 3 + Math.Sign(sNum.Length Mod 3) To 1 Step -1 sRead.Append(Read3Digits(Mid(sNum, iStart, iLen), i)) iStart += iLen : iLen = 3 Next End If Return sRead End Function Public Sub New() strDecimal = GetDicemal(0) 'lay thong tin ve cham thap phan strThousand = GetDicemal(1) ' lay thong tin ve dau cach hang ngan End Sub End Class