Archive

Archive for June, 2012

การส่ง parameter หรือ data ให้กับ activity [Android เก็บเอามาเล่า] ต่อ

มีเพิ่มเติมต่ออีกในเรื่องของการ ส่งผ่านข้อมูลไปยัง activity (newActivity)อื่นในขณะที่สร้าง activity นั้น ยังมีต่ออีกนิส
ก็เนื่องจากว่า ความต้องการในการใช้งาน ในลักษณะนี้นั้นมี 2 ลักษณะคือ
1 สร้าง activity ที่ 2 แล้วเปิด (Fire and forget) ในกรณีนี้พูดไปแล้วนะครับ ในบทความที่แล้ว
2 สร้าง activity ที่ 2 เปิด แล้วรอ รับค่าส่งกลับ ( First and wait fore response – Ancy callback )
ในบทความนี้เรามาต่อการใช้งานในลักษณะที่ 2
หากเราต้องการ ที่จะ ให้ activity ที่ถูกสร้างขึ้นนั้น นั้นเป็น dialog รับค่าจากผู้ใช้แล้ว ส่งคืนกลับให้กับ activity ที่สร้างมัน (currentActivity) ทำอย่างไร

เรื่องนี้ เรื่องที่ค่อนข้างใช้บ่อยและสำคัญ ครับสำหรับการพัฒนาโปรแกรม เพื่อโต้ตอบกับผู้ใช้ มาดูวิธีการเลยนะครับ
ในการสราง activity แล้วรอ ค่าส่งกลับ เราทำดังนีนะครับ (สมมุติว่า acctivity ปัจจุบันคือ currentAcivity และ activity ที่จะใช้เป็น dialog คือ newActivity)


Intent newIntent = new Intent(this.getApplicationContext(),newActivity.class);
Bundle bundle = new Bundle();
bundle.putString("param1","test");
newIntent.putExras(bundle);
setartActivityForResult(newIntent,REQ_CODE);

** หมายเหตุ – code ด้านบน เขียนใน event อย่างเช่น onClickListener ของ view เป็นต้น

เช่น code เต็ม

   ....
final static int REQ_CODE = 1;
   .....
btnStartAct.setOnClickListener(new View.OnClickListener() {
   public void onClick(View view) {
     Intent newIntent = new Intent(this.getApplicationContext(),newActivity.class);
     Bundle bundle = new Bundle();
     bundle.putString("param1","test");
     newIntent.putExras(bundle);
     setartActivityForResult(newIntent,REQ_CODE );
    });
}

ครับจาก code newActivity เป็น activity ที่เราต้องการสร้าง จาก currentActivity
สำหรับด้านรับข้อมูลด้าน (newActivity)

 Bundle bundle = this.getIntent().getExtras();
 if(bundle != null){
String param1 = bundle.getString("param1");
 }

** ระวังเรื่องการส่งค่านะครับ ในกรณีนี้หากไม่กำหนดค่าให้ param1  ค่าจะเป็น null


ต่อ นะครับ สำหรับการส่งค่ากลับ ให้กลับ currentAcitivity  พร้อมกลับ ส่งการ focus ให้กับ currentActivity ดังนี้

    btnOk.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
      Bundle bundle = new Bundle();
      bundle.putString(“status”, “OK”);

      Intent mIntent = new Intent(); 
      mIntent.putExtras(bundle);

      setResult(RESULT_OK, mIntent);
      finish();
    });
  }

จะเห็นว่าการส่งค่ากลับนั้น ก็ส่งผ่าน Intent โดยใช้ putExtra method แล้วสั่ง finish เลย เป็นการเป็นหน้า activity ไปด้วยเลย สุดท้าย ในด้าน currentActivity ให้เขียน overried method ที่ชื่อว่า  onActivityResult method จะถูกเรียกทันทีหลังจาก newActivity ปิดลงและส่งค่ากลับ ตัวอย่าง code ดังนี้ครับ

@Override protected void onActivityResult(int requestCode,int resultCode,String strdata,Bundle bundle)
{
Log.i(Global.TAG, "MainDriver main-activity got result from sub-activity");
if(resultCode == RESULT_OK)
   {
      // do something here ....
      // รับข้อมูลจาก bundle เหมือนปกติครับ
   }
}

ครับ เป็นอันจบขั้นตอนการ ทำงานทั้งหมดแล้ว หวังว่า จะเป็นประโยชน์ต่อ หลายท่านที่กำลังค้นหาข้อมูลส่วนนี้อยู่นะครับ s_teerapong2000@yahoo.com

Categories: Andriod

การส่ง parameter หรือ data ให้กับ activity [Android เก็บเอามาเล่า]

June 25, 2012 Comments off

ในบางครั้งในการส้ราง activity นั้นเราอาจจะต้องการส่งผ่านข้อมูล ให้กับ activity เพื่อควบคุมอะไรบางอย่าง หรือ ให้ activity เอาไปประมวลผล อะไรก็ตาม  ลองมาดูกันนะครับว่า มีวิธีการอย่างไร

สมมติว่า activity ปัจจุบัน ให้ชื่อว่า currentActivity และต้องการสร้าง activity ใหม่ (ให้ชื่อว่า newActivity ) พร้อมกับส่งผ่าน parameters ไปให้กับ newActivity

Intent I = new Intent(getApplicationContext(),newActivity.class);
i.putExtra(“keyName”,”value”);
startActivity(i);

จาก code นะครับการส่งผ่าน ทำได้โดยการ ใช้ method putExtra ของ intent เพื่อส่งผ่าน ค่า โดยให้ “keyName” เป็น ชื่อหรือตัวแปรที่ต้องการ และ “value” เป็นค่าที่ต้องการส่งนะครับ

ส่วนทาง newActivity ที่ต้องการรับ ค่าที่ส่งมาให้ทำดังนี้ครับ

Bundle extras = getIntent().getExtras();
If(extras != null){
String value = extras.getString(“keyName”);
}

เป็นอันว่า เรียบร้อยครับการส่งผ่านข้อมูลไปยัง activity ที่ต้องการในขณะที่สร้าง acivitiy นั้น
สำหรับเรื่องนี้ มีต่อนะครับ …

Categories: Andriod

การใช้งาน Deletgate เบื้องต้น

ครับ delegate น่าจะเป็นประเด็นที่ค่อนข้าง จะสับสน กับ นักพัฒนามือหัดขับ หลาย ๆ ท่าน ( ผมด้วย ) ในบทความนี้ จะพูดถึงการใช้งานแบบ พื้นฐานของ delegate เพื่อ พื้นที่สำคัญก้าวต่อไปของ การใช้ delegate ใน C# .net

Image
Delegate เป็น base type ตัวหนึ่งใน .NET  ซึ่งมันเป็น class สำหรับการสร้างและใช้ delegate ในขณะ runtime ครับอย่างที่ทราบกันนะครับโดย พื้นฐานแล้ว Delegate คล้ายกับ Function Pointer ใน C++   ซึ่งใช้ในการอ้างอิง method ต่างกันก็ตรงที่  delegate นั้น method ที่จะใช้อ้างอิง ต้องมี หน้าตาเหมือนกับ delegate type ที่ประกาศไว้ หน้าตาเหมือน ก็คือ มี return type และ parameters เหมือน กัน
มีการให้ข้อมูลเรื่องการใช้งาน delegate มากมาย แต่คำถามที่เกิดขึ้นในใจ เพื่อน ๆ ก็คือ  การใช้งาน เราจะใช้งานมันเมื่อไร หรือ ความจำเป็นอะไร ที่จะทำให้เราต้องเอา delegate มาแก้ปัญหา หล่ะ แน่นอนครับ มันต้องมีสิครับ ก็คือว่า ในการพัฒนา Application อาจมีบางครั้งหรือบางเหตุการณ์ที่เราอาจ ต้องแก้ปัญหาด้วยการ ส่งผ่าน method ไปให้ กับ method ตัวอื่น เพื่อใช้งาน ( method , function , procedure คืออันเดียวกันนะครับ)    ดังนั้นเราก็สามารถใช้ delegate ในการจัดการกับปัญหานี้ได้

เพื่อให้เห็นภาพ วิธีที่ดีก็คือ ดูจากตัวอย่างครับ  ตัวอย่างนี้ยืมมาจาก นี่ครับ http://msdn.microsoft.com/en-us/library/900fyy8e%28v=vs.71%29.aspx

จากภาพ ในขั้นตอนแรก ก็คือการ ประกาศ delegate ชื่อว่า MyDelegate มี parameter   ตัว คือ  I เป็น integer และ ไม่มี return type คือ กำหนดให้เป็น void
ต่อไป เป็นการ สร้าง function ชื่อว่า DelegateFunction ซึ่งเป็น ฟังก์ชันที่จะให้ delegate object มาใช้ หรือชี้มาที่ function นี้  จะเห็น ว่า มี parameter และ return type เหมือน กับ delegate ที่ประกาศไว้ นะครับ
ต่อไปเป็นการนำไปใช้ ในขั้นตอนที่ 3 เราส่งผ่าน delegate ให้กับ TaskADelegate fucion โดยผ่านเป็น parameter type เป็น delegate ที่ประกาศไว้
และสุดท้าย TaskADelegate function ก็ถูกเรียกใช้ใน public static void Main()   จากคำสั่งนี้  TaskADelegate(new MyDelegate(DelegateFuction));

จากคำสั่งที่เห็น รวบรัดไปหน่อยสำหรับ มือใหม่ ขอแตกออกเป็น 2 คำสั่งดังนีครับ
MyDelegate  delCall = new MyDelegate(DelegateFunction);
TaskADelegate(delCall);

จะเห็นว่าเหมือนการสร้าง object นะครับ  delCall เป็น object ของ MyDelegate และ ชี้ไปที่ DelegatFunction  แล้วก็ส่งผ่านไปให้ function TaskADelegate เรียกใช้ งานอีกที หรือ จะเรียก delCall( ตัวเลขใด ๆ ) เหมือนเรียกใช้ function เลยก็ได้ แล้วแต่การใช้งานครับ
ตัวอย่าง ง่าย ๆ ที่แสดงถึงการใช้ประโยชน์ Delegate คือ การที่ 2 delegate นำมา combine กันได้ หรือมารวมกันได้ โดยใช้ operator + หรือ –  

รูปนำมาจาก http://msdn.microsoft.com/en-us/library/900fyy8e%28v=vs.71%29.aspx

1 จากรูปตัวอย่าง เราประกาศ delegate ชื่อว่า myDelegate มี parameter ชนิด string  และไม่มี return type
2 ใน class ประกาศ method ที่มี signature เดียวกับ delegate มี 2 function คือ Hello และ Goodbye ทั้งสอง พิมพ์ ตัวอักษร ออกหน้าจอ ว่า Hello, “xxx” และ Good bye , “xxx” ตามลำดับ
3 หลังจากนั้นใน function main เราประกาศ ตัวแปร delegate  a,b,c,d
–    ให้ a point ไป Hello
–    ให้  b pointไป Goodbye
–    และ c = a + b;
–    และ d = c – a;
ผลการ run จะเห็นว่า เมื่อสั่ง c(); จะมี  การทำงาน ของ a() ต่อด้วย b()
เช่นเดียวกันกับ d() จะมีแค่ การทำงานของ b() เนื่องจาก ได้ลบ การทำงาน ของ a() ไปแล้ว
สรุปก็คือ instance ของ delegate สามารถนำมา บวกและ ลบกันได้ โดยที่บวก เป็นการเอา function มาทำงานต่อกัน และ – เป็นลบส่วนการทำงานของ function ที่ลบออกไป ครับ  เราอาจใช้
c += a; ก็ได้นะครับ นั่นเป็นวิธีการใช้ delegate แบบพื้น นะครับ ในบทความถัดไป จะพูดถึงการใช้งาน ขั้นสูงขึ้นต่อไปนะครับ s_teerapong2000@yahoo.com

Categories: C# .NET

เรื่อง การใช้ external libraries กับ Android ( external Jar )

เก็บเอาประสบการณ์มาเล่าให้ฟังต่อ เรื่อง external library เราจะเอามาใช้อย่างไร (ผมใช้ eclipse)
ครับเรื่องการใช้ external library ก็หมายถึงเราต้องการ เราสิ่งที่คนอื่นเขาเขียนแล้วมาใช้ซึ่งจะมาใหรูปแบบของ ไฟล์นามสกุล .jar การทำก็ไม่ใช่เรื่องยุ่งยากอะไร ถ้าทราบวิธี
นอกจากจะทำให้เราเรียกใช่งานได้แล้ว มันยังควบรวมเขาเป็นส่วนหนึ่งของ .apk file ในกรณีที่เรานำไปใช้ หรือ ทดสอบใน Emulator

ขั้นตอนก็มีดังนี้นะครับ
1.ให้เราสร้าง folder ที่ว่า libs [ชื่ออะไรก็ได้] ไว้ภายใต้ project folder
2. ให้ copy Jar file และ อื่น ๆ ที่รายล้อม jar file เช่น directory armeabi มาไว้ใน folder ที่เราสร้าง [libs]
3. หลังจากนั้นเรา click ขวาที่ jar file นั้น แล้วเลือก Build Path > Add to build path  เราจะเห็น ว่า jar file นี้ถูกเพิ่มเข้าไปใน Referenced Library ใน project  เป็น อันเสร็จครับ

Categories: Andriod

Debug Certificate expired Error ?????

Imageหวัดดีครับเพื่อน ๆ นักพัฒนาทั้งหลาย ช่วงนี้มีโอกาสได้ทำงานที่ต้องใช้ andriod นิสหน่อย ก็เลยเก็บประสบการณ์เอามาเล่าเผื่อว่า
จะเป็นประโยชน์ไม่มากก็น้อย แด่เพื่อน ๆ นักพัฒนาทั้งหลาย  เรื่องนี้มันก็เกี่ยวกับ Error ที่น่าปวดหัวสำหรับนักพัฒนามือใหม่หัดขับ ที่อยากเริ่มต้นพัฒนาโปรแกรม ด้วย Andriod นะครับ

ในส่วนของการ ติดตั้งนั้นผมก็คงไม่ต้องพูดถึงนะครับ มีให้ดูมากมายใน Net ทั้งที่เป็น ภาษาไทยและภาษาอังกฤษ แต่ที่ผมจะเอามาแบ่งปันก็เห็นจะเป็นเรื่อง Error ที่ จั่วหัวไว้นี่แหละครับ

มาดูปัญหาเริ่มแรกกันก่อนนะครับ คือว่า การสร้างโปรแกรมด้วย Andriod นั้นจะต้องมีการ ลงทะเบียน certificate ของผู้ใช้งาน หรือผู้พัฒนาโปรแกรม เพื่อให้สามารถตรวจสอบที่มาที่ไปของโปรแกรมได้นั่นเอง ปัญหาก็คือในบางครั้งหลังจากติดตั้ง Andriod SDK แล้ว (ผมใช้กับ eclipse นะครับ)  สมมติว่า สมบูรณ์แล้ว เราก็เริ่มที่จะเขียน ทดสด 1 โปรแกรม สั้น ๆ ยอดฮิต  “helloWorld” หลังจากนั้น ก็ทำการ compile และ run ครับ   (อย่าลืม Setup emulator นะครับ) ปรากฎว่า ได้ข้อความที่แสดงข้อผิดพลาดออกมา ประมาณว่า  ” Error generating final archive: Debug certificate expired on …….  Unknown    Android Packaging Problem ”

ครับ อืมเวรละซิ

เอา Error message ค้น google ดู ครับ โห ออก มามากมาย ซึ่งสามารถแก้ไขได้ดังนี้

– ให้ลบ debug.keystore ออก ซึ่งอยู่ใน (c:\users\[username]\.andriod\ – windows7 นะคราบบบ) ออกไป เดี๊ยว sdk จะสร้างให้ใหม่

– แล้ว ทำการ clean ใน project ที่กำลังทำงานอยู่ แล้วลอง Run ใหม่   ( หลายท่านทำแค่นี้จบครับ ทำงานได้เลย แต่ของกระผมไม่จบ )

ทำไม ?????

หาต่อ อีก หลายที่ให้ คำแนะนำมาว่า เอางี้ ถ้า วิธีนั้นไม่ work ลองวิธีนีดู ให้สร้าง debug.keystore  ( แม่งเองเลยดิ ) ทำไง หล่ะ

ก็ command line เลยครับ ใช้ตามนี้เลยนะครับ

C:\Users\teerapong\.android>keytool -genkey -keypass android -keystore debug.key store -alias androiddebugkey -storepass android -validity 1000 -dname “CN=Androi d Debug,O=Android,C=US”

[ในกรณีนี้ผม แอบไป add ตัวแปร path ชี้ไปที่  C:\Program Files\Java\jre6\bin ไว้แล้วเน่อ คิดว่าหลายท่านคงทราบนะครับ เพราะคำสั่ง keytool มานเป็น ของ jre]

ก่อน run ก็ให้ลบของเดิมออกก่อนนะครับ ในขั้นตอนแรก นั่นแหละครับ หลังจากนั้นจึง run คำสั่ง  จบ ไหม   NO !!!!

โอย อะไร กันหล่ะนี้   หาไปอีกหลายที่ เขาก็บอกกันแค่นี้ ครับ ไปต่อไม่ได้เลย ผมล่วงไป อย่างน้อย 50 เส้น

กลับไปอ่าน online document ใหม่อีกรอบ หนึ่งปรากฏว่า เขาก็บอกไว้ครับ ว่าหากทำจนครบแล้วมันไม่ work ให้มาดู อีกที่หนึ่ง สิว่า เครื่องที่ท่านพัฒนาอยู่ นั้น calendar เป็น Gregorian หรือป่าว ถ้าไม่เป็น debug.keystore สร้างให้ตายไงก็ Expired ครับ     –> เหรอ !!!!!!

เขาก็แนะว่า ให้ท่านเปลี่ยน ให้เป็น Gregorion calendar แล้วก็ สร้าง debug.keystore แล้ว ก็ใช้ได้เลย หลังจากนั้นก็เปลี่ยนกลับมาเป็น none-Gregorion date ก็จบ จบจริงครับ โล่งไป  ฮะ ฮะ ยังมีหลายท่านสงสัยว่า แล้ว ไอ้ Gregorion calendar  ยังไง (ผมเองก็ไม่รู้ว่ายังไง เขาแนะต่อว่า ให้ไปเปลี่ยน ใน Reginal and language ให้เป็น  Us เป็นต้น ก่อนแล้วก็ทำ key แล้วเอา key มาใช้แล้วเปลี่ยนกลับ จบครับ หลังจากนี้ ก็ จบปัญหา ครับ

หวังว่ามันจะเป็นประโยชน์ไม่มากก็น้อย สำหรับเพื่อน ๆ นักพัฒนาทั้งหลาย ขอให้สนุกกับการเขียนโปรแกรม นะครับ

s_teerapong2000@yahoo.com

s.teerapong@gmail.com

Categories: Andriod

การสร้างตารางข้อมูลแบบ Hierarchy Data Structure เพื่อใช้กับ Treeview control

Treeview control เป็น control ที่ใช้บ่อยกับงาน Interface ที่แสดงข้อมูลในรูปแบบที่เป็น ระดับสัมพันธ์ กันหรือเรียกว่า Hierarchy Data Structure ซึ่งเป็นโครงสร้างแบบเดียวกับ Tree สำหรับ ผู้พัฒนาในระดับต้น มักต้องประสบปัญหาความยุ่งยากเมื่อนึกถึงโครงส้รางแบบนี้ ลองมาดูวิธีการตัวอย่างนี้เป็น แนวทางในการ ในการนำไปประยุกค์ใช้งานต่อไปนะครับ

ความต้องการในการใช้งาน หรือ Business Requirement

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

การแก้ปัญหา
–    สร้างโครงสร้างข้อมูลให้ได้ตาม รูปแบบที่ต้องการ (Hierarchical data)
–    สร้าง logic ในการอ่านข้อมูล (Recursive Funciton)
–    ส่งแสดงใน Treeview
โครงสร้างข้อมูลตัวอย่าง จากรูปด้านล่าง เรามี ตารางข้อมูล ทีมี field เป็น NODE_DESCRIPTION , NODE_ID, NODE_PARENT_ID

ให้ NODE_PARENT_ID เป็นข้อมูลบอก ว่า recode ไหน ที่เป็น parent ของมัน โดยดูที่ NODE_ID ครับ เท่านี้เราก็สามารถที่จะมีโครงสร้างตารางข้อมูล ที่จะแสดง กับ  TreeView ได้แล้วนะครับ  ซึ่งก็จะได้โครงสร้างดังนี้นะครับ
[ตารางชื่อ tblHierarchyTree – SqlServer Express 2005]

ต่อมา สร้าง Data Access ให้กับข้อมูลข้างต้นนะครับ

–          สร้าง class ไว้เก็บค่าจากตาราง ให้ชื่อว่า HierarchyNode

–          List ของ HierarchyNode เป็น class ชื่อ HierarchyNodes [สังเกตว่าเติม s นะครับ ]

*จาก code ตัวอย่างอาจจะดู รวบรัด มือใหม่อาจจะงง ก็แยก class HierarchyNode ออกจาก HierachyNodes ก็ได้ครับแล้วค่อย ทำเป็น List ทีหลัง  ให้เป็น file ชื่อ HierarchyNode.cs

หลังจากนั้น แล้วทำ Data Access Class เพื่ออ่านค่าจาก ตาราง tblHierarchyTree ตาม code ด้านล่างนะครับ


ผมให้ class ชื่อว่า    HierarchyNodeADO นะครับ เต็ม ๆ จะได้ดังนี้นะครับ  ไฟล์ชื่อ HierarchyNodeADO.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;

namespace wHierarchyApp.DAO
{
 public class HierarchyNodeADO
 {
   string connetion = @"Server=.\SQLEXPRESS; User Id=sa;Password=pongratee;Database=test" ;

   public HierachyNodes getAllNODE2()
   {
     string sqlstr = "Select * from tblHierarchyTree order by NODE_ID";
     HierachyNodes result = new HierachyNodes();
     using (SqlConnection con = new SqlConnection(connetion))
     {
        con.Open();
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = con;
        cmd.CommandText = sqlstr;
        SqlDataReader reader = cmd.ExecuteReader();
        while (reader.Read())
        {
          result.Add(new HierachyNodes.HierarchyNode()
          {
            NODE_ID = int.Parse(reader["NODE_ID"].ToString()),
            NODE_DESCRIPTION = reader["NODE_DESCRIPTION"].ToString(),
            NODE_PARENT_ID = int.Parse(reader["NODE_PARENT_ID"].ToString())
          });
        }
     }
     return result;
  }
 }
}

หลังจากนั้นเราก็ เปิด Form1.cs หรือ สร้างในชื่อใด ๆ ก็ได้นะครับแล้ว ก็ วาง Treeview contrl และ button ลงไปครับ
Treeview สำหรับการแสดงผล ส่วน Button สำหรับการ สั่งให้ดึงค่าจาก ตารางมาแสดงผลนะครับ ดู code ด้านล่างเป็นส่วนที่ สำคัญสำหรับการแสดงผลนะครับ  ลองดู logic ของ code และทำความเข้าใจดูนะครับ ตรงไปตรงมาไม่ยากนะครับ ผมละส่วนอื่น ไว้ในฐานที่เข้าใจนะครับ code ส่วนนี้จะเป็นส่วนที่ ดังข้อมูลจาก DataBase มาแสดงผลผ่าน HierarchyNodeADO class [Data access class]

s_teerapong2000@yahoo.com

Categories: C# .NET, Windows Forms