วันศุกร์ที่ 30 สิงหาคม พ.ศ. 2556

ขั้นตอนการติดตั้ง Derby แบบ Embedded (ไม่ต้องติดตั้ง Server Service) บน iReport 5.1.0

1. ดาวน์โหลดไฟล์ Derby แล้วแตก Zip ไฟล์ออก ในตัวอย่างนี้ได้แตกไฟล์ออกที่ C:\

2. เปิดโปรแกรม iReport Designer แล้วเลือก Menu: Tools->Options ดังรูป



วันพฤหัสบดีที่ 28 พฤษภาคม พ.ศ. 2552

การเขียนและอ่านข้อมูลใน Excel โดยใช้ C#

ในตัวอย่างนี้จะสร้างเอกสารไฟล์ Excel แล้วใส่ข้อมูลลงไป หลังจากนั้นจะอ่านข้อมูลในเอกสาร Excel แล้วแสดงข้อความเป็น MessageBox

เตรียมการ
1. เปิด Project ใหม่แล้ววางปุ่มบนฟอร์ม
2. ใส่ Code ต่อไปนี้

private void button1_Click(object sender, EventArgs e)
{
   //ช่วงที่ 1 เตรียมสร้างเอกสาร
   object missing = System.Reflection.Missing.Value;
   Excel.Application exApp = new Excel.ApplicationClass();
   exApp.Visible = true;

   Excel.Workbook exBook = exApp.Workbooks.Add(missing);
   Excel.Worksheet exSheet = (Excel.Worksheet)exBook.Sheets["Sheet1"];
   exSheet.Name = "Example";

   //ช่วงที่ 2 เขียนข้อมูลลงไฟล์ Excel
   exSheet.Cells[1, 1] = "TEST";
   exSheet.Cells[1, 2] = "ABCD";

   //ช่วงที่ 3 อ่านข้อมูลจากเอกสาร Excel สามารถเขียนได้สองแบบ
   MessageBox.Show((string)((Excel.Range)exSheet.Cells[1,2]).Text);
   MessageBox.Show(exSheet.get_Range("A1", "A1").Value2.ToString());

}

3. ทดสอบโปรแกรม

วันพุธที่ 25 มีนาคม พ.ศ. 2552

การแก้ปัญหาเรื่องรูปแบบวันใน .Net

ปัญหาพบบ่อยในการจัดการวันเวลาที่พบคือ
1. ปัญหา พ.ศ. กับ ค.ศ.
2. รูปแบบวันที่ระหว่างฐานข้อมูลกับตัว Windows ไม่ตรงกัน เช่น ใน MySQL รูปแบบ Default คือ yyyy-mm-dd ส่วนใน Windows คือ dd/mm/yyyy (ขึ้นอยู่กับการกำหนดค่าใน windows)

สำหรับการแก้ปัญหาในเรื่องดังกล่าวทำได้โดย

ปัญหา พ.ศ. กับ ค.ศ.
ปัญหานี้แก้โดยกำหนด CultureInfo ให้เป็นรูปแบบที่ต้องการเช่น หากต้องการเปลี่ยนรูปแบบให้เป็น ค.ศ ก็ให้กำหนดค่าเป็น "en-US"
ตัวอย่าง Code

using System.Globalization;
.....

DateTimeFormatInfo myDTFI = new CultureInfo("en-US", false).DateTimeFormat;
Console.WriteLine(DateTime.Now.ToString(myDTFI));

ปัญหารูปแบบวันไม่ตรงตามที่ต้องการ
ปัญหานี้แก้โดยกำหนดรูปแบบวันตามที่ต้องการในขณะแปลงเป็นข้อความ
ตัวอย่าง Code

Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd", myDTFI));

จากตัวอย่างข้างต้น เมื่อใช้รวมกัน จะพิมพ์ข้อความออกมาในรูปแบบดังนี้
เช่น วันที่ 16 มกราคม พ.ศ. 2552 วันนี้พิมพ์ออกมาจะได้

2009-01-16

วันอาทิตย์ที่ 15 มีนาคม พ.ศ. 2552

เทคนิคการควบคุมคอนโทลหลายๆ ตัวในเวลาเดียวกัน

เวลาจะ Disable หรือ Enable คอนโทลในฟอร์ม จะใช้ควบคุมผ่าน Property ที่ชื่อว่า Enable โดยการสั่งงานไปยังคอนโทลแต่ละตัวโดยตรง แต่หากในฟอร์มนั้นมีคอนโทลเยอะๆ การเขียนโปรแกรมเพื่อที่จะปิดเปิดหลายๆ ตัวในเวลาเดียวกันเป็นเรื่องที่ลำบากพอสมควร ยิ่งหากมีการปรับเปลี่ยนคอนโทลภายในฟอร์มในขณะทำงานจริงด้วยแล้วยิ่งปวดหัวใหญ่
เทคนิคง่ายๆ ที่ใช้ควบคุมฟอร์มคือการใช้ Property ที่ชื่อว่า tag ซึ่งอยู่ภายในคอนโทลทุกตัวแล้ว มีขั้นตอนดังนี้

1. กำหนดค่าภายใน tag ที่เราต้องการควบคุม เช่น ใส่คำว่า lock ลงใน Property นั้น
2. ทำการควบคุมคอนโทลโดยใช้เงื่อนไขตรวจสอบว่า tag นั้นเป็น string ที่มีค่าตามที่เรากำหนดไว้รึเปล่า ในที่นี้กำหนดค่าคือ lock โดยใช้ code ควบคุมดังนี้

foreach(Control ctrl in this.Controls)
{
    if((ctrl.Tag as string) == "lock")
    {
        ctrl.Enabled = true;
    }
}


หรืออาจจะเขียนเป็นฟังก์ชั่นไว้ใช้ก็สะดวกดี เช่น

private void disableForm(bool status)
{
    foreach(Control ctrl in this.Controls)
    {
        if(ctrl.Tag as string) == "lock")
        {
            ctrl.Enabled = status;
        }
    }
}

วันจันทร์ที่ 15 ธันวาคม พ.ศ. 2551

การสร้างและใช้งาน Collection.Generic

Generic เป็นเครื่องมือที่ช่วยให้ผู้พัฒนา Collection Class สามารถนำ Class ที่สร้างไว้นำกลับมาใช้งานได้ง่ายขึ้นโดยไม่จำเป็นต้องคำนึงถึงชนิดของตัวแปรที่บรรจุอยู่ใน Collection Class เหล่านั้นในตอนออกแบบ แต่จะทำการกำหนดชนิดของตัวแปรให้กับ Class เมื่อจะนำ Class เหล่านั้นไปใช้งาน

ตัวอย่าง
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace ConsoleApplication9
{
     // กำหนดตัวแปรเป็นชนิด T ภายใต้เครื่องหมาย "< >"
    public class myCollection<T>
    {
         // นำชนิดตัวแปรนั้นมาใช้งานเช่นเดียวกับชนิดตัวแปรอื่นๆ
        T[] myStack = new T[50];

        public T this[int idx]
        {
            get
            {
                return myStack[idx];
            }
            set
            {
                myStack[idx] = value;
            }
        }

    }

    public class Student
    {
        private String _std;

        public Student(String name)
        {
            _std = name;
        }
        public override string ToString()
        {
            return _std;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // เมื่อนำมาใช้งาน ให้กำหนดชนิดของตัวแปรตามที่ต้องการ ในที่นี้ให้แทนด้วย Class Student ที่ได้กำหนดไว้ (อาจกำหนดเป็น String, Int, ... ก็ได้แล้วแต่จะใช้)
            myCollection<Student>             mCollec = new             myCollection<Student>();

            //หลังจากที่กำหนดเรียบร้อยแล้ว จะสามารถนำตัวแปรนั้นมาใช้งานได้ทันที โดยชนิดของตัวแปรนั้นจะเป็นไปตามที่กำหนดไว้ในขั้นตอนการประการตัวแปร
            mCollec[0] = new Student("Jor");
            mCollec[1] = new Student("Ann");
            mCollec[2] = new Student("Aae");

            for(int item = 0; item < 3; item++)
                Console.WriteLine(mCollec[item]);
            Console.ReadKey();
        }
    }
}

วันพุธที่ 29 ตุลาคม พ.ศ. 2551

เพิ่มเติมกับ IEnumerator, IEnumerable และ ICloneable

จากที่ผ่านมาได้พูดถึงภาพรวมของ Collection Interface ที่ .Net ได้เตรียมไว้ คราวนี้จะมาดูรายละเอียด ของ Interface 3 ตัวคือ IEnumerator, IEnumerable และ ICloneable (ที่จริงจะกล่าวเฉพาะ IEnumerator และ IEnumerable แต่ในตัวอย่างมีการใช้งาน ICloneable ด้วยก็เลยกล่าวเพิ่มไปซะเลย)

IEnumerator เป็น interface พื้นฐานเพื่อให้ class ที่อ้างถึง interface นี้สามารถใช้ foreach ได้ ภายในมีสมาชิกดังนี้
    Methods
  • MoveNext ระบุให้เลื่อน element ปัจจุบันไป 1 ช่อง
  • Reset สังให้ current กลับไปจุดเริ่มต้น

    Properties
  • Current ดึง element ปัจจุบันจาก collection

IEnumerable เป็น interface ที่จะทำการส่งคลาส IEnumerator ไปยังคำสั่ง foreach ภายในมีสมาชิกดังนี้
    Methods
  • GetEnumerator ส่งค่า enumerator ที่จะส่งไปยัง foreach

ICloneable เป็น interface ที่กำหนดให้คลาสที่ประกาศต้องมีความสามารถในการ clone ตัวมันเอง

    Methods
  • Clone ทำการ clone ตัวมันเองแล้วส่งค่านั้นกลับไป

ตัวอย่าง Code:
ตัวอย่างต่อไปนี้จะเป็นการสร้าง single linklist โดยไม่ใช้คลาสในกลุ่ม collection ของ .Net แต่จะกำหนดโครงสร้างทั้งหมดเองตามลักษณะดังนี้

|--------------- MyList -----------------|
|---Node---|   |---Node---|   |---Node---|
|Value|Next|-->|Value|Next|-->|Value|Next|

จากโครงสร้างดังกล่าวจะมีคลาสสองตัวคือ MyList และ Node โดย MyList จะเป็น collection ของ Node ภายใน Node จะมีสมาชิกภายในคือ Value เก็บค่าตัวเลขที่ต้องการบันทึก และ Next เก็บที่อยู่ของ Node ถัดไป


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

namespace LinkListDemo
{
    // ประกาศคลาส Node
    public class Node : ICloneable //ประกาศใช้ ICloneable
        public int Value;
        public Node Next;
 
        public Node()
        {
            _value = 0;
        }
 
        public Node(int nValue)
        {
            _value = nValue;
        }
 
        public override string ToString()
        {
            return _value.ToString();
        }
 
        #region ICloneable Members
        public object Clone()
        {
            return new Node(_value);         }
        #endregion
    }
 
    // ประกาศคลาส MyList
    public class MyList : IEnumerator, IEnumerable, ICloneable
    {
        private Node _firstNode;
        private Node _curNode;         private Node _lastNode;
 
        public MyList()
        {
            _firstNode = new Node(); //ตำแหน่ง 1.1
        }
 
        public bool MoveNext()
        {
            _curNode = _curNode.Next; //ตำแหน่ง 1.2
            return !(_curNode == null);
        }
 
        public void Reset()
        {
            _curNode = _firstNode; //ตำแหน่ง 1.3
        }
 
        public object Current //ตำแหน่ง 1.4
        {
            get
            {
                if (_curNode != null)
                {
                    return _curNode;
                }
                else                 {
                    throw new InvalidOperationException();
                }
            }
        }
 
        public void Add(Node newNode)
        {
            if (_curNode == null)
            {
                _firstNode.Next = newNode;
                _curNode = newNode;
                _lastNode = newNode;
            }
            else
            {
                _lastNode.Next = newNode;
                _lastNode = newNode;
            }
        }
 
        public void Add(int newValue)
        {
            Node newNode = new Node(newValue);
            this.Add(newNode);
        }
 
        #region IEnumerable Members
        public IEnumerator GetEnumerator() //ตำแหน่ง 2
        {
            return (IEnumerator)Clone();
        }
        #endregion
 
        #region ICloneable Members
        public object Clone()
        {
            Node tmpNode = _curNode;
            MyList newList = new MyList();
            _curNode = _firstNode.Next;
            while (_curNode != null)
            {
                newList.Add(_curNode.Value);
                _curNode = _curNode.Next;
            }
            return newList;
        }
        #endregion
    }
 
    class Program //โปรแกรมเรียกใช้ class MyList
    {
        static void Main(string[] args)
        {
            MyList myList = new MyList();
            for (int cnt = 0; cnt < 10; cnt++)
            {
                myList.Add(new Node(cnt));
            }
            foreach (Node node in myList)
            {
                Console.WriteLine(node);
            }
            Console.ReadKey();
        }
    }

ในการวนรอบของ foreach นั้นคำสั่ง foreach จะเรียก GetEnumerable() (ตำแหน่ง 2) เพื่อเรียก object collector ขึ้นมาโดยที่ object collector ที่คืนกลับนั้นคลาสจะต้องประกาศ IEnumerator ไว้ด้วย หลังจาก foreach ได้ object collector จะมีขั้นตอนการดำเนินการดังนี้
  1. เรียก MoveNext(ตำแหน่ง 1.2) เพื่อเลื่อนตำแหน่งของ element ไปยังจุดถัดไป ถ้าผลของการ MoveNext ส่งกลับมาเป็น true จะทำงานในข้อ 2 ต่อ ถ้าเป็น false จะหยุดการทำงาน
  2. ส่งค่าใน element ออกไปผ่าน property Current (ตำแหน่ง 1.4)
  3. วนกลับไปทำข้อ 1 ใหม่

จากขั้นตอนดังกล่าวจะเห็นว่าเมื่อเริ่มต้นนั้นการวนรอบของ foreach นั้นตำแหน่งของ Current นั้นจะต้องชี้ไปยังตำแหน่งก่อนหน้าค่าแรก (ในกรณีที่เป็น array ที่มีตำแหน่งเริ่มต้นที่ array[0] ตำแหน่งของ current จะต้องชี้ที่ตำแหน่ง -1) เนื่องจาก foreach จะเรียกใช้คำสั่ง MoveNext (ตำแหน่ง 1.3) ก่อนแล้วจึงส่ง element ใน collector ออกไป ดังนั้นในตอนที่สร้าง MyList ขึ้นมาจึงได้สร้าง node ใหม่ให้กับ _firstNode ในทันทีเพื่อป้องกันความผิดพลาดที่จะเกิดจากการอ่านข้อมูลจาก object ที่ไม่มีการอ้างถึง

วันอังคารที่ 28 ตุลาคม พ.ศ. 2551

ทำความรู้จัก Collection Interface ใน .Net

ใน .Net ได้จัดเตรียมเครื่องมือสำหรับสร้างคลาส Collector ไว้หลายชนิดด้วยกัน หนึ่งในนั้นคือกลุ่ม Interface เพื่อให้คลาสกลุ่ม Collector ที่สร้างขึ้นมานั้นสามารถเชื่อมต่อการทำงานกับภายนอกได้ Interface ที่ .Net ได้จัดเตรียมไว้ให้มีหลายตัว เช่น   
  • IEnumerator และ IEnumerable  ทำให้คลาสที่ inherit จาก interface นี้สามารถใช้คำสั่งวนรอบ foreach ได้
  • ICompare และ IComparable ทำให้คลาสที่ inherit จาก interface นี้สามารถทำการจัดเรียงข้อมูลภายในได้
  • ICollection  เป็นฐานของคลาสใน System.Collection
  • IList สืบทอดมาจาก ICollection อีกต่อหนึ่ง และเป็นฐานของ non-generic lists
  • IDictionary ทำให้คลาสที่ inherit สามารถทำงานได้ในลักษณะเดียวกับคลาส Dictionary
  • IDictionaryEnumerator เหมือนกับ Dictionary แต่สามารถใช้ร่วมกับคำสั่ง foreach ได้ (คลาส Dictionary ไม่สามารถใช้คำสั่ง foreach ได้)
  • IHash คลาสที่สืบทอดมาจะต้องมีคุณสมบัติการทำฟังก์ชั่น Hash

วันศุกร์ที่ 24 ตุลาคม พ.ศ. 2551

การใช้งาน Collections ใน .Net

การเขียนโปรแกรมส่วนใหญ่จะมีการใช้งาน Collections รวมด้วยเสมอเช่น การใช้งาน ListBox ก็จะมี Property Indexs หรือแม้แต่การใช้งาน DataSet ก็จะมี Tables, Columns, Rows ก็ล้วนเป็น Collections ด้วยกันทั้งสิ้น คราวนี้หากเราต้องการสร้าง Class ที่ต้องใช้ความสามารถดังกล่าว ตัวอย่าง การสร้างรายชื่อนักเรียนภายในห้อง เราก็จะสร้างคลาส ClassRoom ภายใน ClassRoom จะมี Property Students ซึ่งจะเก็บรายชื่อนักเรียนทั้งหมดไว้ ซึ่งจะมีโครงสร้างดังนี้

    Class จะมีทั้งหมด 3 class ด้วยกันคือ
  1. Student เป็นตัวแทนนักเรียนแต่ละคนในชั้นเรียน
  2. StudentList เป็นตัวแทนรายชื่อนักเรียนทั้งหมดในชั้นเรียน class นี้จะนำเอาเทคนิคการใช้ Collection มาใช้
  3. ClassRoom เป็นตัวแทนห้องเรียน แสดงการนำ Collection ที่ประการศไว้มาใช้ โดยนำคลาส StudentList มาเป็น Property หนึ่งของ ClassRoom

    ตัวอย่าง Code:

    public class Student
    {
        private int _id;
        private string _name;
        private string _surname;

        Student()
        {
            _id = 0;
        }
       
        public Student(int id, string name, string surname)
        {
            _id = id;
            _name = name;
            _surname = surname;
        }

        public int Id
        {
            get{ return _id; }
            set{ _id = id; }
        }

        public string Name
        {
            get{ return _name; }
            set{ _name = value;}
        }

        public string Surname
        {
            get{ return _surname; }
            set{ _surname = value; }
        }

        public override string ToString()
        {
            return _name + " " + _surname;
        }
    }

    จาก Student ข้างต้นจะมี attribute ที่เป็น private คือ _id, _name, _surname มี Properties 3 ตัวคือ Id, Name, Surname และมี Constructor 2 ตัว นอกจากนี้ยังมี method 1 ตัวคือ ToString() เพื่อให้สามารถแปลงเป็น string ได้เลย

    public class ClassRoom
    {
        public class StudentList : CollectionBase // ประกาศ Nested Class
        {
            public void Add(Student std)
            {
                if ((std.id == 0) || (std.Name == null) || (std.Surname == null))
                {
                    Console.WriteLine("Error: Student not initialize.");
                    return;
                }
                List.Add(std); //เพิ่ม std ลงใน list
            }

            public void Remove(Student std)
            {
                List.Remove(std); //ลบ std ออกจาก list
            }

            public Student this[int stdIndex] // ประกาศ property เพื่อให้สามารถมองในลักษณะ array
            {
                get { return (Student)List[stdIndex]; }
                set { List[stdIndex] = value; }
            }
        }

        private string _className;
        private string _Advisor;
        public StudentList Students;

        public ClassRoom()
        {
            Students = new StudentList(); // สร้างคลาส StudentList
        }

        public string ClassName
        {
            get { return _className; }
            set { _className = value; }
        }

        public string Advisor
        {
            get { return _Advisor; }
            set { _Advisor = value; }
        }

        public override string ToString()
        {
            StringBuilder str = new StringBuilder();
            str.Append("Class Room: " + _className + "\n");
            str.Append("Adviser: " + _Advisor + "\n");
            str.Append("Student: \n");
            int cnt = 1;
            foreach (Student std in Students)
            {
                str.Append("\t" + cnt++.ToString() + ") " + std + "\tid: " + std.id + "\n");
            }
            return str.ToString();
        }
    }

    จาก Code ข้างต้นภายในคลาส ClassRoom จะมีคลาสภายในคือ StudentList ซึ่งจะถือว่าเป็น Nested Class โดยที่ StduentList จะ Inherited Class มาจาก CollectionBase โดยภายใน CollectionBase จะมี property ที่สำคัญคือ List หลังจากที่ประกาศคลาสเรียบร้อยแล้ว ได้นำคลาส StudentList มาใช้กับ property Students

    public class Program
    {
        static void Main(string[] args)
        {
            ClassRoom c1 = new ClassRoom();
            c1.Advisor = "Tanapat Warahakit";
            c1.ClassName = "p1";
            c1.Students.Add(new Student(1001, "Tanapat", "Warahakit"));
            c1.Students.Add(new Student(1002, "Tanapong", "Warahakit"));
            c1.Students.Add(new Student(1003, "Jarutas", "Patthanapanchai"));
            Console.WriteLine(c1);
            Console.ReadKey();
        }
    }

    หลังจากที่ประกาศคลาส Student, StudentList และ ClassRoom เรียบร้อยแล้วก็ถึงเวลานำคลาสที่เตรียมไว้มาใช้ดังตัวอย่างข้างต้น

วันอังคารที่ 21 ตุลาคม พ.ศ. 2551

การติดต่อ XML โดยใช้ XmlDocument

ต่อจากตอนที่แล้ว ที่กล่าวถึงการติดต่อ XML แบบ SAX ตอนนี้จะกล่าวถึงการติดต่อแบบ DOM ซึ่งจะเป็นการโหลดข้อมูลทั้งหมดเข้าหน่วยความจำแล้วสร้างโครงสร้างข้อมูลแบบ tree ขึ้นมาในหน่วยความจำ จึงทำให้เราสามารถท่องไปยังส่วนต่างๆ ของข้อมูลได้โดยง่าย นอกจากนั้นยังสามารถจัดการข้อมูลได้โดยง่าย เช่น การเพิ่ม ลบ หรือแก้ไขข้อมูล แต่ข้อเสียของการดำเนินการแบบนี้คือหากข้อมูลมีขนาดใหญ่จะต้องมีหน่วยความจำจำนวนมากมารองรับด้วย และการดำเนินการทั้งหมดนี้จะดำเนินการได้หลังจากโหลดข้อมูลทั้งหมดขึ้นหน่วยความจำแล้ว

ตัวอย่าง code

วันอาทิตย์ที่ 19 ตุลาคม พ.ศ. 2551

การติดต่อไฟล์ xml ด้วย xmlTextReader

การติดต่อไฟล์ XML ด้วย XmlTextReader จะเป็นการติดต่อแบบ SAX (Simple API for XML) ซึ่งจะมีลักษณะการทำงานเป็นแบบ อ่านข้อมูลเข้ามาทีละชุด โดยข้อมูลที่เข้ามานั้นอาจจะเป็น element หรือ text หรือ attribute ก็ได้ ดังนั้นข้อดีของการติดต่อไฟล์ XML ด้วย SAX คือสามารถติดต่อไฟล์ XML ที่มีขนาดใหญ่มากๆ ได้ดีเนื่องจากจะเป็นการอ่านข้อมูลมาทีละชุดจึงทำให้ใช้เนื้อที่ในหน่วยความจำน้อย และสามารถทำงานได้รวดเร็วเนื่องจากทำการอ่านข้อมูลมา 1 ชุดแล้วก็ดำเนินการประมวลผลได้เลยไม่ต่อรอให้ระบบอ่านข้อมูลมาจนหมด ส่วนข้อเสียคือการเพิ่ม/ลดข้อมูล และ การท่องไปยังข้อมูลต่างๆ ในไฟล์ XML จะทำได้ยากเพราะการทำงานของ SAX นั้นจะเป็นการทำงานเรียงจาก element แรกเรื่อยไปจนกระทั่งถึง element สุดท้าย

ตัวอย่าง Code

วันศุกร์ที่ 3 ตุลาคม พ.ศ. 2551

เรื่องของ Nested Class ใน .Net

ก่อนอื่นต้องทำความรู้จัก Nested Class ก่อนว่าคืออะไร พิจารณา Code ต่อไปนี้
class Container
{
class Nested
{
Nested() {}
}
}
จากตัวอย่าง code ข้างต้นจะเห็นว่าภายใน class Container จะมี class ภายใน ซึ่งเราจะเรียกว่า Nested Class โดยปกติแล้้ว การมองเห็น Nested จะเป็น private แต่เราสามารถเปลี่ยนรูปแบบการมองเห็นเป็นแบบอื่นได้ เช่น public, protected เป็นต้น
สำหรับการอ้างถึง Container Class (class นอก) จาก Nested Class (class ภายใน) สามารถทำได้โดยใช้ constructer ช่วย ดังตัวอย่างต่อไปนี้
public class Container
{
public class Nested
{
private Container m_parent;
public Nested()
{
}
public Nested(Container parent)
{
m_parent = parent;
}
}
}
การอ้างถึง Nested Class จากภายนอกสามารถทำได้โดย
Container.Nested nest = new Container.Nested();

เกร็ดเล็กๆ น้อยๆ ของ XML กับ DataSet ใน .Net

- การอ่าน XML เข้ามาใน DataSet
DataSet ds = new DataSet();
ds.ReadXml("XmlFile.xml");
- เวลาเขียนข้อมูลใน DataSet เป็นไฟล์ XML ใช้คำสั่ง
ds.WriteXML("XmlFile.xml");
- ภายหลังเรียกคำสั่ง ReadXml ถ้ามี table อยู่ก่อนหน้าใน dataset ข้อมูลเก่าจะหาย ดังนั้นหากต้องการอ่านข้อมูลเข้าข้อมูลหลายๆ ตาราง ให้สร้าง DataSet 2 ตัวโดยให้ตัวหนึ่งอ่าน แล้วค่อย copy() table ไปยัง DataSet อีกตัวหนึ่ง
- การใช้คำสั่ง clone() ของ DataTable จะเป็นเพียงการสร้าง Table ใหม่ซึ่งมีโครงสร้างทุกอย่างเหมือน Table ต้นฉบับแต่ไม่ได้คัดลอกข้อมูลภายในมาด้วย
- การใช้คำสั่ง copy () ของ DataTable นั้นคล้ายกับ clone() แต่จะต่างกันตรงที่คำสั่ง copy() จะคัดลอกข้อมูลนั้นมาด้วย
- ชนิดของข้อมูลของ column ที่อยู่ภายใน table ซึ่งได้จากการอ่าน ReadXML จะมีเฉพาะ string เท่านั้น
- ข้อมูลใน XML ที่เขียนลงไฟล์จะมีเพียง Table เดียวเท่านั้นคือ table แรกที่อยู่ใน DataSet (หรือมีค่า index เป็น 0)
- หากต้องการหาข้อมูลที่อยู่ใน DataSet ทำได้สองวิธีคือ 1. ใช้คำสั่ง find และ 2. ใช้คำสั่ง select โดยแต่ละวิธีจะมีรายละเอียดดังนี้
1. หากใช้คำสั่ง find จะต้องทำการกำหนด PrimaryKey ให้กับ Table ที่ต้องการค้นหาข้อมูลก่อน ซึ่งจะต้องกำหนด Keys โดย Keys ที่จะกำหนดนั้นต้องมี DataType เป็น DataColumn[] (Array ของ DataColumn) เมื่อเขียน Code จะมีลักษณะดังนี้
public string GetData(String itemID)
{
DataColumn[] keys = new DataColumn[1];
keys[0] = dataSet1.Tables["TableName"].Columns["ColumnName"];
dataSet1.Tables["TableName"].PrimaryKey = keys;
DataRow findRow = dataSet1.Tables["TableName"].Rows.Find(itemId);
if (findRow != null)
{
return findRow["ItemName"].ToString();
}
else
return "";
}
2. การใช้คำสั่ง select จะมีรูปแบบเหมือนกับการ filter ข้อมูล ผลลัพธ์ที่ได้จะอยู่ในรูป array ของ DataRow (DataRow[]) Code การทำงานมีดังนี้
public string GetData(String itemID)
{
DataRow[] findRow = dataSet1.Tables["TableName"].Select("ColumnName=" + itemID);
if(findRow.Length != 0)
{
return findRow[0]["ColumnName"].ToString();
}
else
{
return null;
}

วันอังคารที่ 30 กันยายน พ.ศ. 2551

วิธีการเข้า web ที่ถูก block ด้วย proxy

คำเตือน การรับส่งข้อมูลผ่าน open proxy อาจจะมีการดัก password ไว้ได้ ดังนั้นหากต้องการใช้หรือจำเป็นต้องใช้งาน open proxy ต้องแน่ใจว่าไม่มีการรับส่งข้อมูลที่มีความสำคัญในขณะรับส่งข้อมูลผ่าน open proxy
จากปัญหาการ block web site บางแห่งจากองค์กรของรัฐ (อย่างไม่เป็นธรรม)  เราสามารถเข้าถึง web ที่ถูก block ได้โดยใช้งานผ่าน proxy server ซึ่งมีบริการฟรีทั่วโลก 
การค้นหา proxy และการติดตั้งมีดังนี้
ขั้นแรก เราต้องหา proxy ที่จะใช้บริการก่อนโดยค้นจาก google ใช้คำค้นดังนี้ free proxy ตัวอย่าง proxy ที่ได้จะมีลักษณะดังนี้ http://www.publicproxyservers.com/page1.html 
ขั้นที่สอง ตรวจสอบว่า proxy นั้นสามารถใช้งานได้หรือไม่ ที่ 
http://www.checker.freeproxy.ru/checker/ โดยใช้ host และ port เช่น ข้อมูลที่ได้จาก google บอกว่า host = 123.123.123.123 port = 80 เราก็กรอกข้อมูลเป็น 123.123.123.123:80
ขั้นที่สาม (สำหรับผู้ใช้ที่มีระบบ LAN หรือผู้ใช้ ADSL ผ่านสาย LAN) ติดตั้ง proxy  โดยเลือก 
1. Control Panel -> Internet Options  (แสดงหน้าต่าง Internet Properties)
2. Connections-> LAN settings (แสดงหน้าต่าง Local Area Network (LAN) Settings)
3. ติ๊กถูกที่ Use a proxy server for your LAN .... 
4. กรอก proxy ที่ตรวจสอบแล้วว่าใช้งานได้ ลงในช่อง Address และ Port แล้วคลิ๊กตอบตกลงสองครั้ง

วันอาทิตย์ที่ 28 กันยายน พ.ศ. 2551

แก้ปัญหา "Unable to convert MySQL date/time value to System.DateTime" ใน .Net

เวลาเราต้องการนำข้อมูลจาก DataAdapter ใส่ลงใน DataSet จะใช้คำสั่ง Fill แต่หากในตารางมีข้อมูลประเภท Datetime และข้อมูลภายในมีค่าเป็น null จะทำให้เกิด Exception 
"Unable to convert MySQL date/time value to System.DateTime"
ปัญหานี้สามารถแก้ไขโดยเพิ่มข้อความ 
Allow Zero Datetime=True
ตัวอย่าง คำสั่งการใช้ MySqlConnection
string conStr = "SERVER=" + hn + ";DATABASE=" + db + ";Port=" + pt + ";UID=" + UID + ";PWD=" + PWD + ";Allow Zero Datetime=true;";
MySqlConnection conn = new MySqlConnection(conStr);

วันจันทร์ที่ 15 กันยายน พ.ศ. 2551

วิธีเชื่อมข้อมูล MySql โดยใช้ BindingSource บน .Net

คำเตือน ข้อมูลในส่วนนี้สรุปเอาจากความเข้าใจ โดยการศึกษาและพยายามลองผิดลองถูกเอา อาจจะมีวิธีการอื่นที่ถูกต้องและรัดกุมกว่านี้

สิ่งที่ต้องเตรียม
1. ฐานข้อมูล MySql พร้อมข้อมูล ในที่นี้จะใช้ฐานข้อมูลชื่อ test ภายในฐานข้อมูลมีตาราง 1 ตารางชื่อ table1 ข้อมูลมีดังนี้
==== table1 ====
id name
================
1 abc
2 def
================

2. ติดตั้ง MySql Connector สำหรับ .net

ลงมือทำ

1. สร้าง Project ใหม่ใน Visual Studio

2. เพิ่ม Refence ของ MySql โดยเลือก Project -> Add Reference -> MySQL.Data ดังรูป














3. เพิ่ม using MySql ในหัวของ Form1 ดังนี้

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 MySql.Data;
using MySql.Data.MySqlClient;


4. วาง component ดังรูป















พร้อมกับกำหนด properties ของ component แต่ละตัวดังนี้
- dataset1 ให้เลือก Tables แล้วในช่อง (Collection) จะแสดงปุ่ม '...' ให้กดปุ่มนี้ โปรแกรมจะแสดงหน้าต่างใหม่ ให้กดปุ่ม add จะได้ตารางใหม่ชื่อ Table1 ให้เปลี่ยนเป็นชื่อ table1 (เปลี่ยนตัว T เป็นตัวเล็ก) จากนั้นเลือก Columns ช่อง (Collection) จะแสดงปุ่ม '...' ให้กดปุ่มนี้ จากนั้นโปรแกรมจะแสดง หน้าต่างใหม่ ให้เพิ่ม 2 column แบบเดียวกับที่เพิ่ม table จากนั้นเปลี่ยนชื่อ ColumnName เป็น id และ Name
- bindingSource1 ให้กำหนด properties DataSource = dataSet1, DataMember = table1
- bindingNavigator1 ให้กำหนด BindingSource = bindingSource1
- dataGridView1 ให้กดปุ่มเล็กๆ ตรงมุมขวา (จะมีหน้าต่างๆ เล็กๆ ขึ้นมา) แล้วเลือก ข้อมูลในช่อง Choose Data Source เป็น bindingSource1
5. แก้ไข Source Code ให้เป็นดังนี้ (ขี้เกียจแสดงอธิบายรายละเอียดการใส่ code นะ)

public partial class Form1 : Form
{
private MySqlConnection conn;
private MySqlDataAdapter adp;

public
Form1()
{
InitializeComponent();
}
private void Form1_Load(object
sender, EventArgs e)
{
conn = new
MySqlConnection("database=test;server=localhost;uid=root;pwd=password");
adp = new MySqlDataAdapter();
adp.SelectCommand = new MySqlCommand("SELECT * FROM
table1", conn);
MySqlCommandBuilder cb = new
MySqlCommandBuilder(adp);
conn.Open();
adp.Fill(dataSet1,
"table1");

// ในกรณีที่ไม่ได้สร้าง table ภายใน dataSet1 ตามข้อ 4 ให้เพิ่ม  Code นี้ลงไป

DataColumn dc1 = new DataColumn("id", System.Type.GetType("System.Int32"));
DataColumn dc2 = new DataColumn("Name", System.Type.GetType("System.String"));
DataTable tb = new DataTable("NameList");
dataSet1.Tables.Add(tb);
bindingSource1.DataSource = dataSet1;
bindingSource1.DataMember = "table1";
dataGridView1.AutoGenerateColumns = true;

}


private void Form1_FormClosed(object sender, FormClosedEventArgs
e)
{
conn.Close();
}

private void dataGridView1_CellEndEdit(object sender,
DataGridViewCellEventArgs e)
{
adp.Update(dataSet1.Tables["table1"]);
}
private void
dataGridView1_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e)
{
adp.Update(dataSet1.Tables["table1"]);
}
}


เพิ่มเติม ในกรณีที่ต้องการเชื่อมต่อกับ control อื่นๆ เช่น textbox, combobox ให้ใช้ code ดังต่อไปนี้ในส่วนที่จะเชื่อมต่อกับฐานข้อมูล

ในกรณี textbox

textBox1.DataBindings.Add(new Binding("Text", bindingSource1, "id", true));

ในกรณี combobox

comboBox1.DataSource = dataSet1;
comboBox1.DisplayMember = "table1.Name";
comboBox1.DataBindings.Add(new Binding("Text", bindingSource1, "Name"));



วันพุธที่ 20 สิงหาคม พ.ศ. 2551

ลืม password ของ admin ใน joomla

หากลืม password ของ admin ใน joomla สามารถแก้ไขได้โดยการเปลี่ยน password ใหม่ ให้ดำเนินการดังนี้
1. เข้าไปที่ฐานข้อมูล mysql ของ joomla
2. มองหา table "jos_users"
3. มองหา user ที่เป็น admin
4. แก้ไข password โดยใช้ function md5

ตัวอย่าง SQL ที่ใช้แก้ไข password admin
UPDATE `joomla`.`jos_users` SET `password` = MD5( 'newpassword' ) WHERE `jos_users`.`username` = 'admin';

จะเป็นการเปลี่ยน password ของ admin เป็น 'newpassword'

session ใน PHP 4 กับ UTF-8

ในระหว่างการพัฒนา web หนึ่งโดยใช้ notepad++ เป็น editor ในการพัฒนา php ควบคุม session ปรากฎว่าไม่ว่าจะเขียนโปรแกรมอย่างไร ก็จะมีปัญหาเรื่อง php แจ้งเตือนว่าไม่สามารถใช้งาน session ได้เพราะว่า cookie ซ้ำ หรือ ไม่สามารถส่ง cookie ได้ ดังตัวอย่าง

Warning: session_start() [function.session-start]: Cannot send session cookie - headers already sent by (output started at C:\AppServ\www\guestbook\guestbook_del_confirm.php:1) in C:\AppServ\www\guestbook\guestbook_del_confirm.php on line 2

Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at C:\AppServ\www\guestbook\guestbook_del_confirm.php:1) in C:\AppServ\www\guestbook\guestbook_del_confirm.php on line 2


จากตัวอย่างดังกล่าวปัญหาเกิดจากในตอนพัฒนาโปรแกรมนั้นการ encoding ตัวอักษรได้เลือกเป็น utf-8 ดังนั้นการแก้ปัญหาดังกล่าวทำได้โดยการเปลี่ยน encodeing อื่นๆ ที่ไม่ใช้ utf-8 เช่น utf-8 without BOM หรือ ascii เป็นต้น

การทำ link ใน html เป็นแบบ button

ปกติเวลาเราทำ link ใน html จะใช้คำสั่ง


<a href="url_link">link</a>


แต่บางครั้งเราอาจต้องการให้ link ที่แสดงนั้นเป็นปุ่มเพื่อให้สอดคล้องกับปุ่มอื่นๆ หรือ เพื่อความสวยงาม คำสั่งที่ใช้สร้าง link คือ


<input type="button" onclick="window.location.href='url_link'" value="link_text">



โดยที่ url_link คือ url ของ link ที่จะไป ส่วน link_text คือ ข้อความที่แสดงบนปุ่ม

หมายเหตุ ในหนังสือบางเล่มอาจใช้คำสั่งภายใน onclick เป็น "window.navigate('link_text')" ก็สามารถจะใช้ได้เช่นกัน แต่เฉพาะกับ ie เท่านั้น จะใช้ไม่ได้กับ firefox ดังนั้นเพื่อให้สามารถทำงานได้ทั้ง ie และ firefox ก็ควรจะใช้คำสั่งที่แนะนำในข้างต้น

วันศุกร์ที่ 1 สิงหาคม พ.ศ. 2551

วิธีทำให้สามารถพิมพ์ DOS กับเครื่องพิมพ์ USB Port ใน Windows XP

1. ให้ทำการ Share Printer

2. เรียก dos โดยใช้คำสั่ง cmd แล้วพิมพ์คำสั่งต่อไปนี้

net use lpt1: //comname/shareprinter/ Persistent:yes


หมายเหตุ
comname -> ชื่อคอมพิวเตอร์ที่ share เครื่องพิมพ์
ในกรณีที่ไม่ผ่านระบบเครื่องข่ายหมายถึงเครื่องตัวเอง(อาจจะใช้หมายเลข ip:127.0.0.1 แทนก็ได้)
shareprinter -> ชื่อเครื่องพิมพ์ที่ทำ share



3.ระบบ dos พร้อมพิมพ์เรียบร้อยแล้ว

วันพฤหัสบดีที่ 10 กรกฎาคม พ.ศ. 2551

ลำดับการเรียก Exception ใน C#

การเกิด Exception ใน C# กรณีที่เป็น Nested ให้พิจารณาตัวอย่างต่อไปนี้


using System;
using System.Text;

namespace DemoEsception
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Point A");
try
{
Console.WriteLine("Point B");
// Try to convert wrong format
Console.WriteLine(int.Parse("abc"));
Console.WriteLine("Point C");
}
catch (FormatException e)
{
Console.WriteLine("Catch exception:{0}",e);
}
Console.WriteLine("Point D");
}
catch (Exception e)
{
Console.WriteLine("Outer exception:{0}",e);
}
Console.WriteLine("Point E");
Console.ReadKey();
}
}
}


ผลลัพธ์ที่ได้
Point A
Point B

Catch exception:System.FormatException: Input string was not in a correct format. at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal) at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info) at System.Int32.Parse(String s) at DemoEsception.Program.Main(String[] args) in D:\Data\Visual Studio 2008\Projects\DemoEsception\DemoEsception\Program.cs:line 17
Point D
Point E


สังเกตว่าใน code นี้เกิดความผิดพลาดขึ้นเมื่อเกิดความพยายามเปลี่ยนตัวอักษร abc ให้เป็นตัวเลขโดยใช้คำสั่ง int.Parse("abc") ซึ่งจะทำให้เกิด FormatException ขึ้น และเมื่อเกิด Exception ขึ้นนั้นโปรแกรมจะข้าม Point C แล้วทำงานในส่วนของ exception แล้วกลับไปทำงานยัง Point D และ Point E จะเห็นว่าโปรแกรมจะไม่เข้าไปดำเนินการ exception ด้านนอกเนื่องจากได้ดำเนินการ FormatException ไปเรียบร้อยแล้ว

พิจาณา Code ต่อไปนี้เพิ่มเติม

using System;
using System.Text;

namespace DemoEsception
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Point A");
try
{
Console.WriteLine("Point B");
// Try to convert wrong format
Console.WriteLine(int.Parse("abc"));
Console.WriteLine("Point C");
}
catch (IndexOutOfRangeException e)
{
Console.WriteLine("Catch exception:{0}",e);
}
Console.WriteLine("Point D");
}
catch (Exception e)
{
Console.WriteLine("Outer exception:{0}",e);
}
Console.WriteLine("Point E");
Console.ReadKey();
}
}
}

ผลลัพธ์ที่ได้
Point A
Point B
Outer exception:System.FormatException: Input string was not in a correct format. at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal) at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info) at System.Int32.Parse(String s) at DemoEsception.Program.Main(String[] args) in D:\Data\Visual Studio 2008\Projects\DemoEsception\DemoEsception\Program.cs:line 17
Point E

จากตัวอย่างข้างต้นได้เปลี่ยนแปลง Exception เป็น IndexOutOfRangeException ซึ่งทำให้เกิด exception ที่ไม่ได้ดักจับไว้ ผลคือ โปรแกรมจะข้ามการดำเนินการ exception ภายในไปยัง exception ภายนอกซึ่งไม่ได้กำหนดชนิดของ exception ไว้จึงทำให้ การดำเนินการใน Point C และ Point D ถูกข้ามไป เมื่อทำงานในส่วน exception เสร็จแล้วโปรแกรมจึงกลับมาดำเนินการใน Point E ต่อไป