มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 4 ปรับแต่งสีพื้นหลังและรูปภาพไอคอนของปุ่มเครื่องมือบนแถบเครื่องมือ (2)


ไม่พูดพล่ามทำเพลงล่ะครับ มาต่อกันเลย

การปรับแต่งสีพื้นหลัง
เราสามารถปรับแต่งการแสดงผลของ editor เช่นสีพื้นหลังหรือรูปแบบตัวอักษรได้ แต่ในตัวอย่างนี้ผมจะแสดงการปรับแต่งสีพื้นของ skin “v2” จากสีเดิมที่ดูเหมือนสีกากีตุ่น ๆ เป็นสีฟ้าสดใสนะครับ

ในการควบคุมการแสดงผลของ editor นั้น มี style sheet ที่เกี่ยวข้อง อยู่ 2 ไฟล์ คือ editor.css สำหรับควบคุมการแสดงผลของ editor บนบราวเซอร์ และ dialog.css สำหรับการควบคุมการแสดงผลของ dialog box / popup window ต่าง ๆ สำหรับการปรับแต่งสีพื้นของกรอบของ editor จากสีกากีตุ่น ๆ มาเป็นสีฟ้าสดใสนั้น ผมจะแก้ที่ editor.css โดยมองหา สไตล์คลาส .cke_skin_v2 .cke_top, .cke_skin_v2 .cke_bottom, .cke_shared .cke_skin_v2 ซึ่งเป็นคลาสที่กำหนดสีพื้นหลังของกรอบ คลาส .cke_skin_v2 .cke_button a, .cke_skin_v2 .cke_button a.cke_off ซึ่งกำหนดสีพื้นหลังของปุ่มเครื่องมือ และคลาส .cke_skin_v2 .cke_button a, .cke_skin_v2 .cke_button a:hover, .cke_skin_v2 .cke_button a:focus, .cke_skin_v2 .cke_button a:active, .cke_skin_v2 .cke_button a.cke_off ซึ่งกำหนดสีของเส้นขอบของปุ่มเครื่องมือ โดยทำการแก้ไข ดังนี้ครับ
editor.css
.
.
.
.cke_skin_v2 .cke_top, .cke_skin_v2 .cke_bottom, .cke_shared .cke_skin_v2 {
background-color: #f0f8ff;
}
.cke_skin_v2 .cke_button a, .cke_skin_v2 .cke_button a.cke_off {
background-color: #0ff8ff;
filter: alpha(opacity=70);
opacity: .70;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
.cke_skin_v2 .cke_button a, .cke_skin_v2 .cke_button a:hover, .cke_skin_v2 .cke_button a:focus, .cke_skin_v2 .cke_button a:active, .cke_skin_v2 .cke_button a.cke_off {
border: solid 1px #f0f8ff;
display: inline-block;
border-radius: 3px;
.
.
.
}

มาดูผลการแก้ไขกันครับ

CKEditor_4_skin_v2_original
ก่อนการปรับแต่ง

CKEditor_4_skin_custom
หลังการปรับแต่ง

ทั้งหมดนี้คือการปรับแต่งสีพื้นหลังของ editor ครับ แต่ว่าสไตล์คลาสหลัก ๆ ทั้งสามส่วนนี้ เพียงเป็นส่วนที่ควบคุมการแสดงผลส่วนใหญ่เท่านั้นครับ ยังมีสไตล์คลาสที่ควบคุมการแสดงผลส่วนอื่น ๆ อยู่อีก ซึ่งหากแนะนำหมดในที่นี้คงจะยาวมาก ๆ จึงขออนุญาตละไว้นะครับ หากเพื่อน ๆ หรือผู้อ่านท่านใด ต้องการปรับแต่งในระดับละเอียดกว่านี้ สามารถเข้าไปแก้ไขในในไฟล์ editor.css และ dialog.css ได้ครับ

อนึ่ง สำหรับ skin “kama” นั้น เราไม่จำเป็นจะต้องแก้ไขไฟล์ style sheet ใด ๆ เลย หากต้องการเปลี่ยนสีพื้นหลัง เนื่องจาก skin ใหม่นี้ มีการเพิ่มความสามารถใหม่ ๆ เข้าไป (skin.js, ckeditor.js) ทำให้เราสามารถกำหนดสีพื้นหลังได้ ด้วยการกำหนดสีพื้นหลังที่ต้องการในขณะที่สร้าง instance ของ editor ได้เลย หรือกำหนดไว้ในไฟล์ config.js ก็ได้ครับ

ตัวอย่าง (การกำหนดสีพื้นหลังที่ต้องการในขณะที่สร้าง instance ของ editor)
<asp:TextBox runat="server" ID="txbEditor1" Width="500" Height="200" TextMode="MultiLine" />
<script type="text/javascript" language="javascript">
CKEDITOR.replace('txbEditor1', {
uiColor: '#F0F8FF',
skin: 'kama',
toolbar: 'Custom'
});

</script>

ตัวอย่าง (การกำหนดรูปแบบการแสดงผลที่ต้องการไว้ในไฟล์ config.js)
CKEDITOR.editorConfig = function(config) {
config.skin = 'kama';
config.uiColor = '#F0F8FF';
config.toolbar = 'Custom'
};

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

อ่านบทความย้อนหลัง
มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 1 เริ่มต้นใช้งาน
มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 2 ปรับแต่งแถบเครื่องมือ
มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 3 ปรับแต่งรูปสื่ออารมณ์
มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 4 ปรับแต่งสีพื้นหลังและรูปภาพไอคอนของปุ่มเครื่องมือบนแถบเครื่องมือ (1)

มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 4 ปรับแต่งสีพื้นหลังและรูปภาพไอคอนของปุ่มเครื่องมือบนแถบเครื่องมือ (1)


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

โครงสร้างของไดเร็กทอรี่ที่เกี่ยวข้อง
ไดเร็กทอรี่ที่เก็บ skin ต่าง ๆ ของ CKEditor นั้นจะอยู่ภายใต้ไดเร็กทอรี่ “skins” โดยจะตั้งชื่อไดเร็กทอรี่ตามชื่อของ skin นั้นๆ เช่น ไดเร็กทอรี่ “kama” สำหรับเก็บไฟล์ต่าง ๆ ของ skin ที่ชื่อ “kama” เป็นต้น เรามาดูโครงสร้างของไดเร็กทอรี่ที่เก็บไฟล์ skin ต่าง ๆ กันครับ
[WebApplicationRootDirectory]
+ [App_Data]
. . .
+ [ckeditor]
. . .
+ [skins]
+ [kama]
+ [images]
–  dialog.css   <– style sheet ของ dialog box
–  editor.css   <– style sheet ของ editor
–  icons.png   <– รูปภาพไอคอนของปุ่มเครื่องมือบนแถบเครื่องมือ
–  skin.js
–  templates.css
+ [office2003]
. . .
+ [v2]
. . .
. . .

จะเห็นได้ว่า CKEditor นั้น ได้เตรียม skin มาให้เราใช้ถึง 3 แบบ คือ v2, office2003 ซึ่งทั้งสองแบบนี้มีอยู่ใน CKEditor รุ่นเก่าด้วย (หมายถึง FCKEditor นะครับ) และที่เพิ่มมาใหม่คือ skin ที่ชื่อ “kama” ซึ่งทางผู้พัฒนาได้เพิ่มขีดความสามารถของ skin ตัวนี้โดยการเรียกใช้ plugins ได้อีกด้วย

ตัวอย่างการเรียกใช้ CKEditor โดยระบุชื่อ skin
<script type="text/javascript" language="javascript"> CKEDITOR.replace('txbEditor1', { skin: 'v2' }); </script>

ตัวอย่าง skin ต่าง ๆ ที่ มีอยู่ใน CKEditor

CKEditor_4_skin_v2
การแสดงผล CKEditor ด้วย skin “v2”
CKEditor_4_skin_office2003
การแสดงผล CKEditor ด้วย skin “office2003”
CKEditor_4_skin_kama
การแสดงผล CKEditor ด้วย skin “kama”

การปรับแต่งรูปภาพไอคอนของปุ่มเครื่องมือบนแถบเครื่องมือ
รูปภาพไอคอนของปุ่มเครื่องมือนั้นถูกเก็บอยู่ในไฟล์ที่ชื่อ icons.png ภายใต้ไดเร็กทอรี่ของ skin นั้น ๆ ไฟล์ icons.png นี้ มีขนาด 16 x 1215 pixel เป็นไฟล์ที่เก็บรวบรวมรูปภาพไอคอนของปุ่มเครื่องมือทั้งหมดไว้ในตัวมันเองเพียงไฟล์เดียว ซึ่งจะสามารถเก็บรูปภาพไอคอน ขนาด 16 x 16 pixel ได้ประมาณ 75 ภาพ และด้วยเทคนิค “CSS Sprite” ทำให้เราสามารถแสดงผลรูปภาพไอคอนของแต่ละปุ่มเครื่องมือแยกกันได้ (ซึ่งการใช้เทคนิค “CSS Sprite” นี้จะช่วยลดปริมาณของการเกิด HTTP Request สำหรับการโหลดรูปภาพลง จาก 63 ครั้งสำหรับแถบเครื่องมือแบบ full เหลือเพียง 1 ครั้ง ซึ่งจะช่วยให้หน้าเว็บถูกโหลดได้เร็วขึ้น — ผู้เขียน)

ในตัวอย่างนี้ผมจะปรับแต่งรูปภาพไอคอนของปุ่มเครื่องมือ ‘Image’, ‘Flash’, ‘Smiley’ และ ‘SpecialChar’ เพียงสี่ปุ่ม พอให้ได้เห็นเป็นแนวทางเท่านั้นนะครับ ซึ่งในการแก้ไขไฟล์ icons.png นั้นคุณจะเลือกใช้โปรแกรมตกแต่งภาพอะไรก็ได้ตามแต่ถนัดครับ ส่วนในตัวอย่างนี้ ผมใช้ GIMP ซึ่งเป็นโปรแกรมโอเพ่นซอร์สที่ใช้สำหรับการตกแต่งรูปภาพ
CKEditor_4_toolbar_icons_modfiy
รูปภาพแสดงการแก้ไขรูปภาพไอคอนของปุ่มเครื่องมือ ‘Image’, ‘Flash’, ‘Smiley’ และ ‘SpecialChar’

CKEditor_4_toolbar_custom
รูปภาพแสดงผลการทดสอบหลังจากการแก้ไขรูปภาพไอคอนสำหรับปุ่มเครื่องมือ ‘Image’, ‘Flash’, ‘Smiley’ และ ‘SpecialChar’ แล้ว

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

อ่านบทความย้อนหลัง
มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 1 เริ่มต้นใช้งาน
มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 2 ปรับแต่งแถบเครื่องมือ
มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 3 ปรับแต่งรูปสื่ออารมณ์

 

มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 3 ปรับแต่งรูปสื่ออารมณ์


บทความคราวนี้เป็นเรื่องที่สามของบทความชุด “มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ” แล้วนะครับ สำหรับคราวนี้เราจะมาปรับแต่งรูปสื่ออารมณ์กันครับ

รูปสื่ออารมณ์ (Emoticon หรือ Smiley)
คือรูปภาพที่ถูกนำมาใช้แสดงแทนอารมณ์ของคนเรา อย่างที่ทราบกันดีว่า “ภาพเพียงหนึ่งภาพนั้นสามารถแทนถ้อยคำได้เป็นพันคำ” ดังนั้น การสื่อสารด้วยรูปสื่ออารมณ์จึงมีส่วนช่วยให้ผู้อ่านสามารถเข้าใจถึงความรู้สึกของผู้เขียนได้โดยง่าย ช่วยให้เกิด “ความรู้สึกร่วม” ในการอ่านข้อเขียนนั้นๆ

สำหรับ CKEditor เองก็มีความสามารถที่จะให้เราหรือผู้ใช้งาน “แทรก” รูปสื่ออารมณ์ลงไปในเอกสารหรือสิ่งพิมพ์ของเราได้ แต่ว่ารูปสื่ออารมณ์ที่มากับ CKEditor นั้นมันช่าง… ไม่งาม ในความรู้สึกผมนะครับ ดังนั้นผมก็จะแก้ไขเจ้ารูปสื่ออารมณ์จากหัวกลมๆสีเหลืองธรรมดาๆ (ดูรูป) เป็นอะไรอย่างอื่นที่ดูดีมีชาติตระกูลขึ้นมานิดนึง

CKEditor_3-Emoticon_Original
โครงสร้างของไดเร็กทอรี่ที่เกี่ยวข้อง
ไดเร็กทอรี่ที่เก็บรูปสื่ออารมณ์ของ CKEditor จะอยู่ในไดเร็กทอรี่ images ซึ่งอยู่ในลำดับชั้นที่สาม (นับจาก ckeditor)
[WebApplicationRootDirectory]
+ [App_Data]
. . .
+ [ckeditor]
+ [images]
+ [lang]
+ [plugins]
+ [a11yhelp]
. . .
+ [smiley]
+ [dialogs]
– smiley.js    <– จาวาสคริปต์ (เข้าใจว่า) สำหรับการแสดงหน้า popup ให้เลือก smiley
+ [images]      <– ไดเร็กทอรี่ที่เก็บรูปสื่ออารมณ์
+ [skins]
+ [themes]
. . .

การแก้ไขรูปสื่ออารมณ์
เมื่อเรารู้ที่เก็บรูปสื่ออารมณ์แล้วเราก็เริ่มแก้ไขรูปได้เลย วิธีแรก ง่ายๆ ค่อนข้างจะเกรียนนิดนึงครับ คือหารูปไอคอนที่เราชอบ มาบันทึกทับรูปเดิมเข้าไป ไม่ต้องแก้ไขโค้ดอะไรทั้งสิ้น เพียงแต่รู้ชื่อไฟล์รูปเท่านั้น (ไฟล์รูปดั้งเดิม มี 21 ไฟล์ดังต่อไปนี้ครับ angel_smile.gif, angry_smile.gif, broken_heart.gif, confused_smile.gif, cry_smile.gif, devil_smile.gif, embaressed_smile.gif, envelope.gif, heart.gif, kiss.gif, lightbulb.gif, omg_smile.gif, regular_smile.gif, sad_smile.gif, shades_smile.gif, teeth_smile.gif, thumbs_down.gif, thumbs_up.gif, tounge_smile.gif, whatchutalkingabout_smile.gif และ wink_smile.gif) แต่วิธีนี้ ถ้าไม่แบ็คอัพรูปไว้รูปต้นฉบับเดิมก็จะหายหมดนะครับ

วิธีที่ 2 วิธีนี้ค่อนข้างง่ายครับ เพราะเราเพียงแค่ปรับแต่งใน config.js เท่านั้นเอง ซึ่งสำหรับการแก้ไขหรือปรับแต่งรูปสื่ออารมณ์นั้นเราจะต้องยุ่งเกี่ยวกับตัวแปร 3 ตัว คือ smiley_path, smiley_images และ smiley_descriptions โดยที่ตัวแปร smiley_path นั้นเป็นตัวแปรที่ระบุ path หรือไดเร็กทอรี่ที่เก็บไฟล์รูปภาพสื่ออารมณ์ครับ เช่น หากเราเก็บชุดรูปสื่ออารมณ์ไว้ภายใต้ไดเร็กทอรี่ [drive]:[website]ckeditorpluginssmileymysmiley เราก็ระบุเพียงแค่ “ckeditor/plugins/smiley/mysmiley/” เท่านั้นครับ หรืออาจจะระบุแบบเต็มเลยก็ได้ เช่น “http://www.mysite.com/ckeditor/plugins/smiley/mysmiley/&#8221; ส่วน smiley_images เป็นตัวแปรอาเรย์ที่เก็บรายชื่อไฟล์รูปสื่ออารมณ์ และ smiley_descriptions เป็นตัวแปรอาเรย์ที่เก็บคำอธิบายของรูปสื่ออารมณ์แต่ละรูปซึ่งเราจะเห็นเมื่อเราเลื่อนเมาส์ไปบนรูปสื่ออารมณ์นั้น ๆ ครับ เอาล่ะครับ มาเริ่มกันเลย

  1. จัดหารูปภาพสื่ออารมณ์ หรือจะสร้างเองก็ได้ครับ แต่ตัวผมเองค่อนข้างจะยอมรับอย่างหน้าบานตาชื่นว่า ฝีมือการใช้งานโปรแกรมตกแต่งภาพ และฝีมือการออกแบบนี่อยู่ในระดับอเวจีเลย จึงขออนุญาตใช้รูปที่มีอยู่แล้วและหาดาวน์โหลดได้ทั่วไปจากในเน็ตก็แล้วกัน นะครับ ซึ่งผมจะนำมาใช้ 2 ชุด คือชุดไอคอนหัวหอม และชุดลิงครับ
  2. เมื่อได้ชุดรูปสื่ออารมณ์มาแล้ว ก็สร้างที่อยู่ให้มันใหม่ ภายใต้ ckeditor/plugins/smiley เช่น ckeditor/plugins/smiley/onion สำหรับชุดหัวหอม และ ckeditor/plugins/smiley/monkey สำหรับชุดลิง
  3. แก้ไขไฟล์ config.js ดังตัวอย่างข้างล่างนี้
    CKEDITOR.editorConfig = function(config) {
    .
    .
    .
    // Custom emoticon/smiley (Onion Set)
    config.smiley_path = ‘Scripts/plugins/smiley/onion/’;
    config.smiley_images = [‘onion_angry.gif’, ‘onion_blush.gif’, ‘onion_cheeky.gif’, ‘onion_cheer.gif’, ‘onion_cool.gif’, ‘onion_crying.gif’,
    ‘onion_dead.gif’, ‘onion_enlightened.gif’, ‘onion_frown.gif’, ‘onion_give_me.gif’, ‘onion_heart.gif’, ‘onion_heart_broken.gif’,
    ‘onion_indecision.gif’, ‘onion_laugh.gif’, ‘onion_not_care.gif’, ‘onion_sad.gif’, ‘onion_sigh.gif’,
    ‘onion_smile.gif’, ‘onion_smoking.gif’, ‘onion_surprise.gif’, ‘onion_thankful.gif’, ‘onion_vomit.gif’];
    config.smiley_descriptions = [‘Angry’, ‘Blush’, ‘Cheeky’, ‘Cheer’, ‘Cool’, ‘Crying’, ‘Dead’, ‘Enlightened’, ‘Frown’, ‘Give Me’, ‘Heart’,
    ‘Heart Broken’, ‘Indecision’, ‘Laugh’, ‘Not Care’, ‘Sad’, ‘Sigh’, ‘Smile’, ‘Smoking’, ‘Surprise’, ‘Thankful’, ‘Vomit’];
    };
    จากนั้นบันทึกไฟล์ config.js ก็เป็นอันเสร็จเรียบร้อยแล้วครับ เท่านี้เราก็จะได้ชุดรูปสื่ออารมณ์อย่างที่เราต้องการนอกเหนือจากที่ CKEditor เตรียมไว้ให้แล้ว และเราก็สามารถนำรูปสื่ออารมณ์นี้มาแทรกไว้ในเอกสารของเราได้ แต่เนื่องจากตัวแปรที่เกี่ยวกับรูปสื่ออารมณ์นี้ ไม่ได้ถูกแยกเป็นชุด ๆ เหมือนกับชุดแถบเครื่องมือ (ซึ่งเราเพิ่มและเรียกใช้โดยระบุชื่อชุดได้) ดังนั้นทุก ๆ ครั้งที่เราสร้าง instance ของ editor เราจะได้ชุดรูปสื่ออารมณ์แบบเดียวกันเสมอไปนะครับ

เอาล่ะครับมาดูผลงานกันสักหน่อยครับ

CKEditor_3-Modified_1
CKEditor กับ รูปสื่ออารมณ์ชุดหัวหอม
CKEditor_3-Modified_2
CKEditor กับ รูปสื่ออารมณ์ชุดลิง

ข้อสังเกต ด้วยวิธีที่ 2 นี้ เราจะใช้ไฟล์รูปภาพจำนวนเท่าใดก็ได้ มากหรือน้อยกว่าจำนวนไฟล์ที่มากับ CKEditor (คือ 21 ไฟล์) ก็ได้ แต่สิ่งที่เราต้องคำนึงถึงก็คือ มิติของรูปสื่ออารมณ์ที่เรานำมาใช้ด้วย (ความกว้าง x ความสูง) และจำนวนของรูป เพราะหากรูปใหญ่ไปหรือมากไปอาจจะเกินเฟรม แลดูไม่งาม หรือส่วนเกินนั้นอาจจะถูกตัดทิ้งไปก็เป็นได้ครับ

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

อ่านบทความย้อนหลัง
มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 1 เริ่มต้นใช้งาน
มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 2 ปรับแต่งแถบเครื่องมือ

มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 2 ปรับแต่งแถบเครื่องมือ


จากบทความตอนแรก เราสามารถใช้งาน CKEditor กับ ASP.NET ในการทำให้คอนโทรล TextBox แปลงโฉมไปเป็น WYSIWYG Rich Text Editor ได้แล้ว สำหรับในตอนที่ 2 นี้ เราจะเริ่มมาปรับแต่ง CKEditor ให้โดนใจกันครับ เริ่มด้วยการปรับแต่งแถบเครื่องมือกันก่อน

ใน CKEditor จะกำหนดแถบเครื่องมือมาให้ 2 แบบ คือแบบ Basic ซึ่งจะมีปุ่มเครื่องมือเฉพาะเท่าที่จำเป็นต้องใช้ และ Full ซึ่งจะมีปุ่มเครื่องมือครบทุกอย่าง

CKEditor_2_Basic
รูปตัวอย่างแถบเครื่องมือแบบ Basic
CKEditor_2_Full
รูปตัวอย่างแถบเครื่องมือแบบ Full

อย่างไรก็ดี เราสามารถกำหนดได้เองว่าต้องการปุ่มเครื่องมืออะไรในแถบเครื่องมือบ้าง ซึ่งเราสามารถทำได้สามวิธีครับ คือ การกำหนดขณะออกแบบ หมายถึงในหน้าเว็บที่ใช้ CKEditor โดยระบุปุ่มเครื่องมือที่ต้องการใช้ในขณะที่สร้าง instance ของ editor วิธีที่สองคือเพิ่มเข้าไปในสคริปต์หลักของ CKEditor (ที่ ckeditor.js) โดยตั้งชื่อให้กับแถบเครื่องมือที่เราสร้าง แล้วเรียกใช้โดยใช้ชื่อที่เราสร้างนั่นเอง (ถ้าอ่านแล้วไม่เข้าใจ เดี๋ยวไปดูโค้ดกันครับ) และวิธีที่สามคือเพิ่มชุดแถบเครื่องมือไว้ที่ configuration file (config.js) แต่ก่อนที่เราจะไปเลือกใช้ปุ่มเครื่องมือในแถบเครื่องมือด้วยตัวเอง เรามาดูกันก่อนว่า ปุ่มเครื่องมือที่ CKEditor เตรียมมาไว้ให้เรานั้นมีอะไรกันบ้าง

[] ระบุขอบเขตของกลุ่มเครื่องมือ ปุ่มเครื่องมือที่มีการทำงานคล้ายคลึงกันจะถูกจัดไว้รวมกันในเครื่องหมาย [ ]
‘-‘ ตัวคั่นระหว่างกลุ่มเครื่องมือ
‘/’ ขึ้นบรรทัดใหม่


กลุ่มเครื่องมือสำหรับการแก้ไขเอกสาร

‘Source’ ดูรหัส html
‘Save’ บันทึก (แต่เท่าที่ผมทดลองมา ปุ่ม ‘บันทึก’ นี้เหมือนไม่ทำงาน ก็เลยไม่แน่ใจว่าจะต้องเพิ่มเติมอะไรที่ไหนอีกหรือไม่ และเนื่องจากปกติผมไม่ได้ใช้ฟีเจอร์นี้ ก็เลย disable มันไว้และก็ยังไม่ได้ค้นคว้าต่อไปว่าจะต้องทำอย่างไรบ้าง)
‘NewPage’ สร้างหน้าเอกสารใหม่ (หากมีข้อมูลเดิมอยู่ก็จะถูกลบหมด)
‘Preview’ ดูหน้าเอกสารตัวอย่าง
‘Templates’ ใช้เทมเพลตที่เตรียมไว้
‘Cut’ ตัดข้อความหรือตัวอักษรที่ต้องการ
‘Copy’ คัดลอกข้อความหรือตัวอักษรที่ต้องการ
‘Paste’ นำข้อความหรือตัวอักษรที่ถูกตัดหรือถูกคัดลอกไว้มาแปะ
‘PasteText’ วางแบบตัวอักษรธรรมดา
‘PasteFromWord’ วางสำเนาจากตัวอักษรเวิร์ด (เท่าที่ทดลองปุ่มนี้มีผลเหมือนกับปุ่ม ‘Paste’)
‘Print’ พิมพ์ข้อความที่พิมพ์ ออกทางเครื่องพิมพ์
‘SpellChecker’ ตรวจสอบการสะกดคำ
‘Scayt’ ตรวจสอบการสะกดคำขณะพิมพ์
‘Undo’ ยกเลิกคำสั่ง
‘Redo’ ทำซ้ำคำสั่ง
‘Find’ ค้นหาข้อความ
‘Replace’ ค้นหาข้อความและแทนที่
‘SelectAll’ เลือกข้อความทั้งหมดที่พิมพ์
‘RemoveFormat’ ลบรูปแบบออก (ผลของคำสั่งนี้จะเหลือเพียงแค่ html tag ปล่าวๆที่ไม่มี attribute ใดๆ เช่น จาก <img align=”left” height=”100″ style=”margin-right: 10px” width=”100″ /> เหลือเพียง <img />)


กลุ่มเครื่องมือสำหรับการสร้างแบบฟอร์ม

‘Form’ แทรกแบบฟอร์มลงในเอกสาร (ผลจากคำสั่งนี้จะได้แท็ก <form  name=”enrolmentForm” id=”enrolmentForm” enctype=”text/plain” method=”post”></form>)
‘Checkbox’ แทรก check box ลงในแบบฟอร์มหรือเอกสาร
‘Radio’ แทรก radio button ลงในแบบฟอร์มหรือเอกสาร
‘TextField’ แทรก text input field ลงในแบบฟอร์มหรือเอกสาร
‘Textarea’ แทรก text input field แบบ multi-line หรือ text area ลงในแบบฟอร์มหรือเอกสาร
‘Select’ แทรก list box ลงในแบบฟอร์มหรือเอกสาร
‘Button’ แทรกปุ่มลงในแบบฟอร์มหรือเอกสาร
‘ImageButton’ แทรกปุ่มแบบรูปภาพ ลงในแบบฟอร์มหรือเอกสารd
‘HiddenField’ แทรก hidden field ลงในแบบฟอร์มหรือเอกสาร<


กลุ่มเครื่องมือสำหรับการจัดรูปแบบตัวอักษร, ข้อความ, รูปภาพ อนิเมชั่น ฯลฯ

‘Bold’ ทำให้ตัวอักษรหรือข้อความในเอกสารเป็นตัวหนา
‘Italic’ ทำให้ตัวอักษรหรือข้อความในเอกสารเป็นตัวเอียง
‘Underline’ ขีดเส้นใต้ตัวอักษรหรือข้อความในเอกสาร
‘Strike’ ขีดเส้นทับตัวอักษรหรือข้อความในเอกสาร (ตัวอย่าง A ก)
‘Subscript’ ทำให้ตัวอักษรหรือข้อความในเอกสารเป็นตัวห้อย
‘Superscript’ ทำให้ตัวอักษรหรือข้อความในเอกสารเป็นตัวยก
‘NumberedList’ แทรกลำดับรายการแบบตัวเลขลงในเอกสาร
‘BulletedList’ แทรกลำดับรายการแบบสัญลักษณ์ลงในเอกสาร
‘Outdent’ ลดระยะย่อหน้า
‘Indent’ เพิ่มระยะย่อหน้า
‘Blockquote’ แทรก block quote ลงในเอกสาร
‘CreateDiv’ แทรกแท็ก div ลงในเอกสาร
‘JustifyLeft’ จัดชิดซ้าย
‘JustifyCenter’ จัดกึ่งกลางหน้า
‘JustifyRight’ จัดชิดขวา
‘JustifyBlock’ จัดพอดีหน้า
‘Link’ แทรก/แก้ไขการเชื่อมโยงลงในเอกสาร
‘Unlink’ ลบการเชื่อมโยงออกจากเอกสาร
‘Anchor’ แทรก/แก้ไข จุดอ้างอิงสำหรับการเชื่อมโยงลงในเอกสาร
‘Image’ แทรกรูปภาพลงในเอกสาร
‘Flash’ แทรก flash animation ลงในเอกสาร
‘Table’ แทรกตารางลงในเอกสาร
‘HorizontalRule’ แทรกเส้นคั่นบรรทัดลงในเอกสาร
‘Smiley’ แทรกรูปสื่ออารมณ์ลงในเอกสาร
‘SpecialChar’ แทรกตัวอักขระพิเศษลงในเอกสาร (เช่น © ® ™ เป็นต้น)
‘PageBreak’ แทรก page break ลงในเอกสาร (สำหรับการพิมพ์ออกทางเครื่องพิมพ์เท่านั้น)


กลุ่มเครื่องมือสำหรับการจัดรูปแบบเอกสาร

‘Styles’ กำหนดรูปแบบหรือลักษณะการแสดงผลของบล็อกข้อความ
‘Format’ กำหนดรูปแบบหรือลักษณะของย่อหน้า
‘Font’ กำหนดรูปแบบหรือลักษณะของตัวอักษร (เช่น Tahoma, Courier New, Arial ฯลฯ)
‘FontSize’ กำหนดขนาดของตัวอักษร
‘TextColor’ กำหนดสีของตัวอีกษร
‘BGColor’ กำหนดสีของพื้นหลัง
‘Maximize’ ขยายขนาดของ editer ให้เต็มเฟรม
‘ShowBlocks’ แสดง/ซ่อนขอบเขตของย่อหน้า
‘About’ แสดงข้อมูลเกี่ยวกับ CKEditor

เอาละครับ เมื่อเรารู้ว่า CKEditor ได้จัดเตรียมปุ่มเครื่องมืออะไรไว้ให้เราใช้งานบ้าง คราวนี้เราจะมาเลือกเฉพาะปุ่มเครื่องมือที่เราต้องการและจัดหมวดหมู่เสียใหม่ของปุ่มเครื่องมือเสียใหม่ให้ตามใจเรากันเลยครับ

วิธีที่ 1 การกำหนดแถบเครื่องมือขณะออกแบบ โดยระบุปุ่มเครื่องมือที่ต้องการใช้ในขณะที่สร้าง instance ของ editor

<asp:TextBox runat=”server” ID=”txbEditor1″ Width=”500″ Height=”200″ TextMode=”MultiLine” />
<script type=”text/javascript” language=”javascript”>
CKEDITOR.replace(‘txbEditor1’, {
toolbar:
[ [‘Bold’, ‘Italic’, ‘Underline’, ‘-‘, ‘Subscript’, ‘Superscript’, ‘-‘, ‘NumberedList’, ‘BulletedList’, ‘-‘, ‘Link’, ‘Unlink’],
[‘Outdent’, ‘Indent’, ‘-‘, ‘JustifyCenter’, ‘JustifyRight’, ‘JustifyBlock’], ‘/’,
[‘Image’, ‘Flash’, ‘Smiley’, ‘-‘, ‘Table’, ‘HorizontalRule’, ‘SpecialChar’] ]
});
</script>

 รูปตัวอย่างการกำหนดแถบเครื่องมือของ CKEditor แบบ ad hoc รูปตัวอย่างการกำหนดแถบเครื่องมือของ CKEditor แบบ ad hoc

วิธีที่ 2 เป็นการเพิ่มชุดแถบเครื่องมือแบบถาวร โดยการเพิ่มลงไปในสคริปต์หลักของ CKEditor โดยตรง และทำการกำหนดชื่อให้กับชุดแถบเครื่องมือชุดใหม่ที่เราสร้างขึ้น วิธีนี้จะยุ่งยากซับซ้อนกว่าวิธีแรกสักนิดเพราะเราจะต้องเข้าไปยุ่งกับโค้ด java script ของ CKEditor (คือไฟล์ ckeditor.js)
เริ่มต้น
1. เปิดไฟล์ ckeditor.js (จะเห็นว่าโค้ด java script ของไฟล์นี้มันจะเรียงกันเป็นพืดไปหมด ดังรูปครับ ดังนั้นจะต้องค่อยๆหา) และค้นหาคำว่า ‘i.toolbar_Basic’ จะพบ ข้อความประมาณนี้
i.toolbar_Basic=[[‘Bold’,’Italic’,’-‘,’NumberedList’,’BulletedList’,’-‘,’Link’,’Unlink’,’-‘,’About’]]; ค่อยๆเลื่อนเคอร์เซอร์ไปจนถึง ‘;’ ที่เป็นตัวปิดประโยคของบรรทัด i.toolbar_Basic นะครับ จากนั้นแทรกโค้ดสำหรับแสดงแถบเครื่องมือที่เราต้องการ ดังตัวอย่างต่อไปนี้ครับ i.toolbar_Custom=[[‘Bold’, ‘Italic’, ‘Underline’, ‘-‘, ‘Subscript’, ‘Superscript’, ‘-‘, ‘NumberedList’, ‘BulletedList’, ‘-‘, ‘-‘, ‘Link’, ‘Unlink’], [‘Outdent’, ‘Indent’, ‘-‘, ‘JustifyCenter’, ‘JustifyRight’, ‘JustifyBlock’], ‘/’, [‘Image’, ‘Flash’, ‘Smiley’, ‘-‘, ‘Table’, ‘HorizontalRule’, ‘SpecialChar’]]; แล้วบันทึกไฟล์ให้เรียบร้อย

2. ที่หน้าออกแบบ
<asp:TextBox runat=”server” ID=”txbEditor1″ Width=”500″ Height=”200″ TextMode=”MultiLine” />
<script type=”text/javascript” language=”javascript”>
CKEDITOR.replace(‘txbEditor1’, {
toolbar: ‘Custom’
});
</script>
บันทึกและทดลองรันดู จะได้ผลเหมือนกับวิธีที่ 1 แต่ด้วยวิธีนี้เราไม่ต้องคอยกำหนดแถบเครื่องมือให้กับ editor ของเราในหน้าออกแบบทุกๆ ครั้ง

หากต้องการกำหนดให้ Custom toolbar ที่เราสร้างขึ้นเป็นค่าปริยายให้กับทุกๆ instance ของ editor ก็สามารถทำได้เช่นกันครับ โดย ค้นหาคำ “i.toolbar=’Full’;” ใน ckeditor.js ซึ่งค่าปริยายที่เขามีให้เราในตอนแรกเลยก็คือ i.toolbar=’Full’; เราก็เพียงแต่ เปลี่ยนเป็น i.toolbar=’Custom’; เท่านั้น จากนั้นก็บันทึกไฟล์ให้เรียบร้อย ต่อไปนี้เวลาที่เราสร้าง instance ของ editor ในหน้าออกแบบ เราก็ไม่จำเป็นจะต้องกำหนดชื่อของชุดแถบเครื่องมืออีกต่อไป เราสามารถเขียนสั้นๆได้ดังต่อไปนี้ครับ

<asp:TextBox runat=”server” ID=”txbEditor1″ Width=”500″ Height=”200″ TextMode=”MultiLine” />
<script type=”text/javascript” language=”javascript”>
CKEDITOR.replace(‘txbEditor1’);
</script>

วิธีที่ 3 วิธีนี้ง่ายกว่าวิธีที่ 2 เยอะครับ และผมก็อยากจะขอแนะนำวิธีนี้ด้วย เพราะว่าวิธีที่ 2 นั้นค่อนข้างจะเกรียนไปสักนิด และทำให้เกิดข้อผิดพลาดได้ง่ายมาก เนื่องจากโค้ด java script ในไฟล์ ckeditor.js นั้น (เข้าใจว่า)เป็นโค้ดที่ถูก compress แล้ว เป็น minification file ทำให้โค้ดมันติดกันเป็นพรืดไปหมด นอกจากนี้ชื่อตัวแปรต่าง ๆ ก็ถูกเปลี่ยน/ย่อให้สั้นลง ทำให้โด้ดอ่านได้ยากขึ้นมาก แต่เนื่องจากวิธีที่ 2 นั้น เป็นวิธีที่ผมเคยใช้เมื่อสมัยยังเป็น FCKEditor อยู่ครับ ก็เลยนำมาลงในบทความด้วย

สำหรับวิธีที่ 3 นี้ เราไม่จำเป็นต้องแก้ไขโค้ดของไฟล์ ckeditor.js ในการเพิ่มหรือแก้ไขแถบเครื่องมือแต่อย่างใด แต่เราจะเพิ่มรายการแถบเครื่องมือลงในไฟล์ config.js แทน ดังตัวอย่าง:
// ไฟล์ config.js
CKEDITOR.editorConfig = function(config) {
// Custom toolbar
config.toolbar_Custom =
[ [‘Bold’, ‘Italic’, ‘Underline’, ‘-‘, ‘Subscript’, ‘Superscript’, ‘-‘, ‘NumberedList’, ‘BulletedList’, ‘-‘, ‘Link’, ‘Unlink’],
[‘Outdent’, ‘Indent’, ‘-‘, ‘JustifyCenter’, ‘JustifyRight’, ‘JustifyBlock’], ‘/’,
[‘Image’, ‘Flash’, ‘Smiley’, ‘-‘, ‘Table’, ‘HorizontalRule’, ‘SpecialChar’] ];
// Minimum toolbar : for just only necessary usage
config.toolbar_Minimum =
[ [‘Source’], [‘Bold’, ‘Italic’, ‘-‘, ‘NumberedList’, ‘BulletedList’, ‘-‘, ‘Link’, ‘Unlink’, ‘-‘, ‘About’] ];
};

เวลาเรียกใช้ในหน้าออกแบบ ก็ระบุชื่อแถบเครื่องมือที่เราต้องการใช้งาน เช่นเดียวกับตัวอย่างโค้ดที่หน้าออกแบบของวิธีที่ 2 ครับ

หากต้องการกำหนดให้ Custom toolbar ที่เราสร้างขึ้นเป็นค่าปริยายให้กับทุกๆ instance ของ editor ก็สามารถทำได้เช่นกันครับ โดยระบุชื่อชุดแถบเครื่องมือที่เราต้องการใช้งานเป็นแถบเครื่องมือปริยาย ใน config.js ได้เลย ดังตัวอย่าง:

// ไฟล์ config.js
CKEDITOR.editorConfig = function(config) {
// Custom toolbar
config.toolbar_Custom =
[ [‘Bold’, ‘Italic’, ‘Underline’, ‘-‘, ‘Subscript’, ‘Superscript’, ‘-‘, ‘NumberedList’, ‘BulletedList’, ‘-‘, ‘Link’, ‘Unlink’],
[‘Outdent’, ‘Indent’, ‘-‘, ‘JustifyCenter’, ‘JustifyRight’, ‘JustifyBlock’], ‘/’,
[‘Image’, ‘Flash’, ‘Smiley’, ‘-‘, ‘Table’, ‘HorizontalRule’, ‘SpecialChar’] ];
// Minimum toolbar : for just only necessary usage
config.toolbar_Minimum =
[ [‘Source’], [‘Bold’, ‘Italic’, ‘-‘, ‘NumberedList’, ‘BulletedList’, ‘-‘, ‘Link’, ‘Unlink’, ‘-‘, ‘About’] ];

config.toolbar = ‘Custom’;
};

ส่วนการเรียกใช้ในหน้าออกแบบก็เพียงแค่ใช้สคริปต์ <script type=”text/javascript” language=”javascript”>CKEDITOR.replace(‘txbEditor1’);</script> เท่านั้นเองครับ

ผมขอจบเนื้อหาของบทความครั้งนี้แต่เพียงเท่านี้ครับ สำหรับคราวหน้าเราจะมาปรับแต่งรูปสื่ออารมณ์กันครับ

อ่านบทความย้อนหลัง
มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 1 เริ่มต้นใช้งาน

มาปรับแต่ง CKEditor ให้โดนใจกันเถอะ ตอนที่ 1 เริ่มต้นใช้งาน


ผมเคยได้พบกับคำถามจากเว็บบอร์ดเกรทเฟรนด์สอยู่บ่อยครั้งว่า มี Text Editor อะไรดี ๆ ที่สามารถใช้งานบนเว็บบราวเซอร์ โดยเฉพาะอย่างยิ่งกับหน้าเว็บที่พัฒนาด้วย ASP.NET ได้บ้าง และก็เห็นมีเพื่อน ๆ หลาย ๆ คนมาช่วยให้คำตอบ รวมถึงตัวผมเองด้วย และจนถึงบัดนี้ผมก็ยังคงคิดว่าเจ้า FCKEditor เนี่ยเป็น “Free” WYSIWYG Text Editor ที่ดีตัวหนึ่ง ที่สามารถรันได้บนเว็บบราวเซอร์ยอดนิยมส่วนใหญ่ โดยไม่มีปัญหาจุกจิกกวนใจมากมายเหมือน Editor ตัวอื่นๆ

ผมใช้งานเจ้า FCKEditor ตัวนี้มานานพอสมควรแล้ว และนอกจากจะแค่เอามาใช้แต่เพียงอย่างเดียว ผมได้เคยงัดแงะโค้ด แก้ไขดัดแปลงบางอย่าง แบบที่เขาเรียกกันหรู ๆ ว่า “customize” น่ะแหละครับ แล้วก็เล็ง ๆ ว่าจะเขียนเรื่องการใช้งานเจ้า Text Editor ที่ฟรีแต่เจ๋งตัวนี้ กับ ASP.NET รวมถึงสิ่งที่ผมเคย customize มันด้วย แต่จนแล้วจนรอดก็ยังไม่ได้ลงมือสักที จนมาถึงบัดนี้ FCKEditor ก็ได้ปรับรุ่นไปขนานใหญ่เสียแล้ว นอกจากนี้ยังเปลี่ยนชื่อใหม่เป็น CKEditor เสียอีกด้วย

ทำความรู้จักกับ CKEditor กันสักเล็กน้อย
CKEditor หรือชื่อเดิมคือ FCKEditor นั้นเป็น WYSIWYG Text Editor บนเว็บบราวเซอร์ ซึ่งหมายความว่า การที่จะนำมันมาใช้งาน เราต้องเอามา”แปะ” ไว้ในหน้าเว็บ และด้วยคุณสมบัติ WYSIWYG ของมันทำให้เราสามารถพิมพ์ข้อความ และจัดรูปแบบข้อความได้ รวมไปถึงการแทรกรูปภาพ แฟลชอนิเมชั่น ฯลฯ ลงไปได้ และเราก็จะได้ผลลัพท์อย่างที่เราพิมพ์ลงไปนั่นเอง

การอนุญาตใช้งาน
CKEditor มีการอนุญาตใช้งาน 2 แบบ คือ Open Source Licence ภายใต้ GPL, LGPL และ MPL สำหรับนำมาใช้งานกับ Open Source Software หรือสำหรับการใช้งานส่วนตัวหรือเพื่อการศึกษา หรือแม้แต่ซอฟแวร์เชิงพาณิชย์ที่ยังไม่สามารถให้การสนับสนุนการพัฒนา CKEditor ได้ และ แบบที่ 2 เป็นการอนุญาตใช้งานในเชิงพาณิชย์ (Commercial License – CKSource Closed Distribution License – CDL) สำหรับบริษัทใดๆที่ไม่มีนโยบายที่จะใช้งานซอฟแวร์ Open Source (อันเนื่องมาจากเงื่อนไขของตัวลิขสิทธิ์เอง–ผู้เขียน) คุณสามารถไปศึกษาเกี่ยวกับการอนุญาตใช้งานได้ที่http://ckeditor.com/license

การนำ CKEditor มาใช้บนหน้าเว็บ ASP.NET
เราสามารถดาวน์โหลด CKEditor ได้จาก http://ckeditor.com/download ครับ ซึ่ง ณ วันที่เขียนบทความนี้นั้นเป็นรุ่น 3.2 ที่เพิ่งออกมาเมื่อ 25 กุมภาพันธ์ 2553 นี่เอง และสิ่งที่เปลี่ยนแปลงสำหรับผมมากที่สุดคือ รุ่นนี้และรุ่นก่อนหน้า (ตั้งแต่รุ่นที่ 3 เป็นต้นมา) จะไม่มีส่วนที่เป็น .NET component อีกแล้ว เหมือนกับว่าทางทีมผู้พัฒนาได้เลิกพัฒนาในส่วนที่เป็น .NET component พร้อม ๆ กับได้เปลี่ยนชื่อเป็น CKEditor นั่นเอง ดังนั้นส่วนที่เป็น .NET component ของ CKEditor นั้นจะหยุดอยู่ที่รุ่น 2.6.3 (FCKEditor 2.6.3) ส่วนรุ่นใหม่ ๆ หลังจากนั้นจะเป็น JavaScript ล้วน ๆ ครับ

เอาล่ะครับ หลังจากที่ดาวน์โหลด CKEditor มาแล้วเราก็แตกออกมาไว้ที่ใดที่หนึ่งในเครื่องเรา แล้วก็มาเริ่มใช้งานกันเลยครับ โดยคัดลอกเฉพาะส่วนที่จำเป็นจากไดเร็กทอรี่ที่เราเก็บ CKEditor ไปไว้ที่ไดเร็กทอรี่รากของ web application ซึ่งเท่าที่ผมลองใช้งาน กับ ASP.NET ส่วนที่จำเป็นต่อการใช้งานและโครงสร้างไดเร็กทอรีมีดังนี้
[WebApplicationRootDirectory]
+ [App_Data]

+ [ckeditor]
+ [images]
+ [lang]               <– เมนูและข้อความช่วยเหลือเป็นภาษาอื่นนอกจากภาษาอังกฤษ
+ [plugins]           <– ปลั๊กอินต่าง ๆ ของ CKEditor
+ [skins]              <– ที่เก็บสกินของ CKEditor ที่มากับชุดโปรแกรมจะมี 3 สกินคือ kama, office2003 และ v2
+ [themes]
ckeditors.js           <– สคริปต์หลักที่ต้องนำไปใช้ในหน้าเว็บ
ckeditor_basic.js
config.js               <– configuration file
เริ่มต้น
1. สร้าง Web Site Project ด้วย Visual Studio 2008
2. เปิดหน้า default.aspx และแทรกจาวาสคริปต์ลงในหน้าเว็บ
<head runat=”server”>

<script src=”ckeditor/ckeditor.js” type=”text/javascript”></script>
</head>
3. สร้าง instance ของ editor
<asp:TextBox runat=”server” ID=”txbEditor1″ Width=”500″ Height=”200″ TextMode=”MultiLine” />
<script type=”text/javascript” language=”javascript”>
CKEDITOR.replace(‘txbEditor1’);
</script>

เพียงเท่านี้ก็เป็นอันเสร็จเรียบร้อยครับ

ผลของการรันหน้าเว็บตัวอย่างบนบราวเซอร์ยอดนิยมครับ

CKEditor_1_Sample_RunIE
IE 8 (8.0.6001.18882)
CKEditor_1_Sample_RunFFMozilla Firefox (3.6.2) CKEditor_1_Sample_RunASApple Safari (4.0.5)
CKEditor_1_Sample_RunOP
Opera (10.10)
CKEditor_1_Sample_RunGC
Google Chrome (4.1.249.1042)
สำหรับการใช้งานในระดับ “ก้าวหน้า” เช่นการใช้งานร่วมกับ jQuery, JavaScript API และอื่นๆ นั้น สามารถดูจากตัวอย่างที่มีมาในชุดโปรแกรมที่ดาวน์โหลดมาได้ครับ ทางผู้พัฒนาได้สร้างหน้าเว็บตัวอย่างในระดับก้าวหน้ามาไว้ให้มากทีเดียว

มีข้อเตือนสำหรับนักพัฒนา ASP.NET สักนิด สำหรับปัญหาน่ากวนใจเพียงเล็กน้อยที่เกิดขึ้นกับเจ้า CKEditor เมื่อทดลองรันครั้งแรก คือ มันจะมีการปะ HTML Tag ให้เราด้วย เมื่อเรา submit จะถูกโวยวายว่า “Server Error in ‘/WebSite1’ Application. —– A potentially dangerous Request.Form value was detected from the client (txbEditor1=”<p>blah blah blah…”).” สังเกตครับว่ามันมีการปะแท็ก “<p>” ข้างหน้าข้อความให้เรา ซึ่ง .NET จะเห็นว่ามันเป็นอันตราย เนื่องจากอาจจะเป็นสคริปต์ที่เขียนขึ้นเพื่อกระทำการอย่างใดอย่างหนึ่งกับข้อมูลของเว็บของเราหรือเว็บอื่นที่เป็นเป้าหมายโดยอาศัยเว็บเราเป็นฐานที่มั่นในการโจมตี ดังนั้นเราจะต้องบอกให้ไม่ต้องทำการตรวจสอบข้อมูลที่ถูกโพสต์จากหน้าเว็บ โดยเพิ่ม attribute ValidateRequest=”false” ลงไปใน Page directive ซึ่งจะเป็นการป้องกันไม่ให้เกิด error นี้ที่เฉพาะหน้าที่มีการใช้งาน CKEditor หรือ อาจจะใส่ไว้ใน web.config ที่ section <page> ดังนี้ครับ <pages validateRequest=”false” /> ซึ่งจะเป็นการบอกว่า ไม่ต้องตรวจสอบข้อมูลที่ถูกโพสต์สำหรับทุกๆหน้า (วิธีหลังนี้ไม่แนะนำครับ เพราะอันตราย) และที่สำคัญคือเมื่อเราบอกให้ไม่ต้องตรวจสอบข้อมูลที่ถูกโพสต์มา เราก็ต้องป้องกันข้อมูลที่ถูกโพสต์เข้ามาด้วยตัวเราเอง โดยใช้ HttpUtility.HtmlEncode ก่อนที่จะบันทึก และใช้ HttpUtility.HtmlDecode ก่อนที่จะนำมาแสดงผล ซึ่งโดยปกติเจ้า CKEditor จะตรวจสอบและแปลงข้อความหรือ Encode ให้เราอยู่แล้วระดับหนึ่ง มีแต่แท็กที่ถูกเพิ่มโดย CKEditor เองเท่านั้นที่ไม่ถูกแปลง

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

มาเขียนเว็บเพจติดต่อกับทวิตเตอร์ด้วย ASP.NET กันเถอะ (ตอนที่ 2)


สำหรับในตอนต่อของบทความ “มาเขียนเว็บเพจติดต่อกับทวิตเตอร์ด้วย ASP.NET กันเถอะ” นี้ ผมจะแสดงรายละเอียดในการใช้งานเจ้า Twitterizer .NET API Library มารับใช้กันครับ แต่ว่า…เนื่องจากมีรายละเอียดค่อนข้างแยะ ผมจึงขออนุญาตนำเสนอเพียงแค่บางคลาส และบางเมธอด ที่จำเป็นต้องใช้งานจริงๆในเบื้องต้นในการที่จะอ่านรายการทวีตของเรามา“ฝัง”ไว้ในหน้าเว็บของเราเท่านั้นนะครับ ส่วนรายละเอียดอื่นๆเพิ่มเติมสามารถเข้าไปอ่านได้ที่ เว็บไซต์ของโครงการ ได้ครับ

เตรียมสภาพแวดล้อมให้พร้อมใช้งาน
หลังจากที่เราแตกไฟล์ Twitterizer.Framework-1.0.1.149.zip(ไฟล์เวอร์ชั่น ณ ขณะเขียนบทความนี้) เราจะได้ไฟล์มาสองไฟล์คือ Twitterizer.Framework.dll และ Twitterizer.Framework.pdb จากนั้นเราก็เริ่มสร้างโครงงานทดสอบกันเลยครับ โดยเริ่มจากเปิดโปรแกรม Visual Studio 2008 แล้วสร้างโครงงานใหม่ ชนิด ASP.NET Web Application ภายใต้ .NET เฟรมเวอร์ค 3.5 สมมติตั้งชื่อโครงงานว่า “myTwitter” เมื่อ Visual Studio สร้างโครงงานใหม่ขึ้นมาแล้ว เราก็ต้องทำการกำหนด reference ไปยัง Twitterizer Library โดยคลิกบนเมนู “Project” เลือกหัวข้อ “Add Reference..” และไปที่ แถบ “Browse” เลือกไฟล์ Twitterizer.Framwork.dll จากโฟลเดอร์ที่เราแตกไฟล์มาเก็บไว้…

มาทำความเข้าใจกับ Twitterizer .NET API Library กันสักนิด
ใน Twitterizer Library มีคลาสให้เราเรียกใช้อยู่หลายคลาสทีเดียว แต่ผมจะขอกล่าวถึงคลาสเฉพาะเท่าที่จำเป็นจะต้องใช้ ซึ่งมีดังนี้ครับ

  • Twitter คลาสนี้ถือเป็นหัวใจของ API Library ชุดนี้ทีเดียว เนื่องจากผู้ออกแบบต้องการให้สามารถใช้งานได้ง่ายที่สุด และมี“ทางเข้า”เพียงทางเดียวเท่านั้นที่จะเข้าไปติดต่อกับทวิตเตอร์ได้ ดังนั้นในการที่เราจะนำ API Library ชุดนี้มาใช้ในการติดต่อกับทวิตเตอร์ เราก็จำเป็นจะต้องสร้าง instance object ของคลาสนี้ขึ้นมาเป็นอันดับแรก
  • TwitterUser คลาสผู้ใช้ทวิตเตอร์ ซึ่งประกอบด้วยข้อมูลต่างๆของผู้ใช้ เช่น UserName ซึ่งก็คือ Name ในทวิตเตอร์, ScreenName ซึ่งก็คือ Username ในทวิตเตอร์, Location, Uri ซึ่งก็คือ Web ในทวิตเตอร์, Description ซึ่งก็คือ Bio ในทวิตเตอร์ — ไม่รู้เหมือนกันว่ามานจะตั้งชื่อต่างจากที่คุ้นเคยกันในเว็บทวิตเตอร์ให้เข้าใจยากๆแบบนี้ทำม้ายยยย angry, NumberOfFollowers,  NumberOfFriends, NumberOfStatuses, ProfileImageUri และอีกมากมาย
  • TwitterUserCollection คลาสที่เก็บ collection ของ TwitterUser ใช้เมื่อต้องการแสดงรายชื่อของผู้ที่เราตามอ่านทวีตและผู้ที่ตามอ่านทวีตของเรา
  • TwitterStatus คลาสนี้ก็สำคัญครับ เพราะมันคือสิ่งที่เราและเพื่อนเราทวีต นั่นเอง
  • TwitterStatusCollection เป็น Collection ของ TwitterStatus
  • TwitterParameters เป็นคลาสที่ใช้เก็บพารามิเตอร์สำหรับกำหนดการทำงานและการอ่านข้อมูลต่างๆของเมธอดในคลาส Twitter เช่นกำหนดจำนวนรายการทวีตที่ต้องการอ่าน, กำหนดชื่อของผู้ใช้ที่ต้องการ เป็นต้น (รายละเอียดของพารามิเตอร์ต่างๆและการใช้งาน จะอยู่ที่ http://code.google.com/p/twitterizer/wiki/GettingStarted#Parameters ครับ)
  • TwitterizerException เป็น คลาส Exception ของ Twitterizer

การติดต่อกับทวิตเตอร์
เราจะเริ่มต้นติดต่อกับทวิตเตอร์ด้วยการสร้าง instance ของคลาส Twitter ขึ้นมาก่อน ดังนี้

using Twitterizer.Framework; // อย่าลืม import namespace เข้ามาด้วยนะครับ
Twitter twitter = new Twitter(“USERNAME”, “PASSWORD”); // UserName และ Password คือชื่อผู้ใช้และรหัสผ่านของทวิตเตอร์

การอ่านข้อมูลของผู้ใช้
การอ่านข้อมูลของผู้ใช้นั้นจะกระทำโดยเมธอด Show() ในคลาส TwitterUserMethods ซึ่งผู้พัฒนา library ชุดนี้ได้อำนวยความสะดวกให้เราโดยการกำหนดให้คลาส Twitter มี property ชื่อ User เป็นชนิด TwitterUserMethods ดังนั้นเราสามารถเรียกใช้เมธอด Show() ได้จาก instance ของคลาส Twitter ได้เลย เช่น twitter.User.Show(“USERNAME”)

ตัวอย่าง:

TwitterUser tu = twitter.User.Show(“USERNAME”); // กำหนด instance object ของ TwitterUser
string screenName = tu.ScreenName; // get twitter’s user name
string userName = tu.UserName; // get twitter’s name
string imageUri = tu.ProfileImageUri; // get twitter user’s image uri
int noOfFollowers = tu.NumberOfFollowers; // get number of followers
int noOfFollowing = tu.NumberOfFriends; // get number of following
int noOfTweets = tu.NumberOfStatuses; // get number of tweets

จากโค้ดตัวอย่างด้านบน เราสามารถเขียนโค้ดให้ย่นย่อ แต่อาจจะอ่านยากสักนิดสำหรับมือใหม่ ได้ดังนี้ครับ (ตัดบรรทัด TwitterUser tu = twitter.User.Show(“USERNAME”); ออกไปเลย)
string screenName = twitter.User.Show(“USERNAME”).ScreenName;
string userName = twitter.User.Show(“USERNAME”).UserName;
string imageUri = twitter.User.Show(“USERNAME”).ProfileImageUri;
int noOfFollowers = twitter.User.Show(“USERNAME”).NumberOfFollowers;
int noOfFollowing = twitter.User.Show(“USERNAME”).NumberOfFriends;
int noOfTweets = twitter.User.Show(“USERNAME”).NumberOfStatuses;

การอ่านรายการทวีต
เมธอดสำหรับอ่านรายการทวีตจากทวิตเตอร์ใน Twitterizer Library มีอยู่หลายเมธอด ซึ่งเมธอดเหล่านี้จะอยู่ในคลาส TwitterStatusMethods สำหรับในบทความนี้ผมจะขอแนะนำแต่เพียง 2 เมธอด คือ
1. HomeTimeline แสดงทุกๆทวีตที่เราและผู้ที่เราติดตามทวีต โพสต์ ซึ่งก็คือรายการทวีตที่หน้า home ข้องผู้ใช้นั่นเอง
2. UserTimeline แสดงทุกๆทวีตที่เราโพสต์ ซึ่งเทียบเท่ากับรายการทวีตที่หน้า profile ของเรานั่นเอง
ตัวอย่าง:
TwitterStatusMethods tsm = twitter.Status;
TwitterStatusCollection ht = tsm.HomeTimeline();
TwitterStatusCollection ut = tsm.UserTimeline();

แต่เนื่องจาก property Status ในคลาส Twitter ในถูกกำหนดให้เป็นไทป์ TwitterStatusMethods อยู่แล้ว ดังนั้นเราสามารถเขียนโค้ดให้กระชับขึ้นได้ดังนี้ครับ

TwitterStatusCollection ht = tsm.HomeTimeline();
TwitterStatusCollection ut = tsm.UserTimeline();

กรณีที่มีการผูกข้อมูลกับคอนโทรลเช่น DataList เราก็สามารถโยน TwitterStatusCollection ไปใส่ DataList ได้โดยตรงเลย เช่น
dlistHomeTimeline.DataSource = twitter.Status.HomeTimeline();
dlistHomeTimeline.DataBind();

นอกเหนือจาก 2 เมธอดข้างบนนี้แล้วยังมี FavoritesTimeline, Mentions() และ Replies() ซึ่งคืนค่ากลับมาเป็น TwitterStatusCollection เหมือนกัน แต่ผมก็ยังไม่ได้ทดลองใช้งาน เลยยังไม่อาจแนะนำได้ อันที่จริงในบทความนี้และตัวอย่างโปรแกรมของบทความนี้เพียงต้องการแสดงวิธีการอ่านรายการทวีตขึ้นมาแสดงในหน้าเว็บเพจเท่านั้น ไม่ได้ตั้งใจว่าจะสร้างเว็บไซต์เลียนแบบทวิตเตอร์มาแข่งกะเขาหรอกนะครับ

นอกจากคลาส TwitterStatusMethods ที่มีเมธอดสำหรับเรียกดูรายการทวีตแล้ว ยังมีคลาสที่ใช้การจัดการกับ Direct Message เพียงอย่างเดียวอีก 1 คลาส คือ TwitterDirectMessageMethods ซึ่งในคลาสนี้มีเมธอด DirectMessages() ที่คืนค่ากลับเป็นชนิด TwitterStatusCollection เช่นเดียวกัน ผมเข้าใจว่าเป็นการอ่านเฉพาะข้อความที่เพื่อนๆส่งถึงเราโดยตรงซึ่งเทียบเท่ากับหน้า DirectMessages ในทวิตเตอร์ (ยังไม่ได้ทดลองใช้งานอีกเช่นกันครับ เขินอาย)

การอ่านข้อมูลของผู้ที่เราติดตามทวีต และผู้ที่ติดตามทวีตของเรา (Following และ Followers)
เราสามารถอ่านข้อมูลของผู้ที่เราติดตามทวีต โดยเรียกใช้เมธอด Friends ในคลาส TwitterUserMethods ซึ่งจะคืนค่าเป็น TwitterUserCollection และในทำนองเดียวกัน เราก็สามารถอ่านข้อมูลของผู้ที่ติดตามทวีตของเรา โดยเรียกใช้เมธอด Followers ในคลาส TwitterUserMethods ซึ่งจะคืนค่าเป็น TwitterUserCollection เช่นกัน
ตัวอย่าง:
// To get all of Followers
TwitterUserMethods tum = twitter.User;
TwitterUserCollection followers = tum.Followers();
foreach (TwitterUser user in followers) {
…    // do something for each twitter user such as display ScreenName, UserName and etc.
}
// To get all of Following
TwitterUserMethods tum = twitter.User;
TwitterUserCollection following = tum.Friends();
foreach (TwitterUser user in following) {
…    // do something for each twitter user such as display ScreenName, UserName and etc.
}

แต่เนื่องจาก property User ในคลาส Twitter ได้ถูกกำหนดให้เป็นไทป์ TwitterUserMethods อยู่แล้ว ดังนั้นเราสามารถเขียนโค้ดให้กระชับขึ้นได้ดังนี้ครับ
// To get all of Followers
foreach (TwitterUser user in twitter.User.Followers()) {
…    // do something for each twitter user such as display ScreenName, UserName and etc.
}
// To get all of Following
foreach (TwitterUser user in twitter.User.Friends()) {
…    // do something for each twitter user such as display ScreenName, UserName and etc.
}

เช่นเดียวกันกับการอ่านรายการทวีต สำหรับกรณีที่มีการผูกข้อมูลกับคอนโทรลเช่น DataList เราก็จะสามารถโยน TwitterUserCollection ไปใส่ DataList ได้โดยตรงเลย เช่น
dlistFollowing.DataSource = twitter.User.Friends();
dlistFollowing.DataBind();

การส่งข้อความทวีต
เราสามารถส่งข้อความทวีตได้ด้วยการใช้เมธอด Update() ซึ่งเป็นเมธอดของคลาส TwitterStatusMethods
ตัวอย่าง:
TwitterStatusMethods tsm = twitter.Status;
tsm.Update(“Your tweet message”);

และเช่นเดียวกันกับการอ่านรายการทวีต property Status ในคลาส Twitter ในถูกกำหนดให้เป็นไทป์ TwitterStatusMethods อยู่แล้ว ดังนั้นเราสามารถเขียนโค้ดให้สั้นลงดังนี้
twitter.Status.Update(“Your tweet message”);


เอาล่ะครับ เมื่อมาถึงบรรทัดนี้ก็หมายความว่า เราสามารถนำเจ้า Twitterizer API Library มาใช้ในการเขียนเว็บเพจเพื่อติดต่อกับทวิตเตอร์ได้ระดับหนึ่งแล้ว คือติดต่อกับทวิตเตอร์ได้, อ่านข้อมูลของผู้ใช้ได้, อ่านข้อมูลรายละเอียดของ Followers และ Following ของผู้ใช้ได้, อ่านรายการทวีตได้ ซึ่งเราสามารถนำไป “ฝัง” ลงในหน้าเว็บของเราได้ และเราสามารถนำไปประยุกต์ต่อได้โดยการทำงานร่วมกับ ASP.NET Ajax โดยใช้คอนโทรล Timer และ UpdatePanel มาช่วย “Refresh” ข้อความทวีต, จำนวน Following ฯลฯ ซึ่งในโค้ดตัวอย่างก็จะแสดงการใช้ ASP.NET Ajax ร่วมกับ Twitterizer API นี้ด้วย 

แหล่งข้อมูลอ้างอิง

แหล่งข้อมูลดาวน์โหลด
Zip
ASPNETTwitterizerAPI.zip — A sample program to integrate Twitter into an ASP.NET website (website “MyTwitter”).

หมายเหตุ ในโปรแกรมตัวอย่างผมได้เก็บค่าของ TwitterUserName และ TwitterPassword ไว้ที่ เซคชั่น appSettings ในไฟล์ web.config ถ้าหากคุณดาวน์โหลดโปรแกรมตัวอย่างไปทดลอง จะต้องไปแก้ไข TwitterUserName และ TwitterPassword ที่ web.config เสียก่อนนะครับ และในขณะรันทดสอบจะต้องเชื่อมต่อกับเครือข่ายอินเทอร์เน็ตด้วยนะครับ เพราะ API Library นี้จะต้องเชื่อมต่อกับเซอร์ฟเวอร์ของทวิตเตอร์ด้วย
CREDIT : Scott Mitchell, “Integrating Twitter Into An ASP.NET Website”, http://www.4guysfromrolla.com/articles/021710-1.aspx

มาเขียนเว็บเพจติดต่อกับทวิตเตอร์ด้วย ASP.NET กันเถอะ (ตอนที่ 1)


ปัจจุบันนี้คงต้องยอมรับนะครับว่าเทรนด์ของการใช้งานอินเทอร์เน็ตโดยเฉพาะอย่างยิ่งการใช้งาน“เครือข่ายสังคม” หรือที่เรามักจะได้ยินใครๆเรียกทับศัพท์เสมอๆ ว่า social network เนี่ยมาแรงมาก (ความจริงเค้าแรงมานานแล้ว) เครือข่ายสังคมเหล่านี้ที่ดังเปรี้ยงปร้างและเราได้ยินกันอยู่บ่อยๆ ก็คงจะหนีไม่พ้น H!5, Facebook, Twitter, Flickr, MySpace และอีกมากมาย

เดิมทีผู้ที่เข้ามาใช้งานเครือข่ายสังคมเหล่านี้ก็คือบุคคลธรรมดาทั่วๆไปเราๆท่านๆนี่แหละ แต่ด้วยกระแสความแรงของเค้า เดี๋ยวนี้เราคงจะเห็นองค์กรธุรกิจหลายๆองค์กร ก็เริ่มนำเอาตัวองค์กรเข้าไปร่วมอยู่ในเครือข่ายสังคมเหล่านี้มากขึ้น ทั้งนี้เพื่อใช้ในการสร้างเครือข่ายกลุ่มผู้ใช้ผลิตภัณฑ์ สร้างโอกาสในการติดต่อสื่อสารกับกลุ่มลูกค้า ซึ่งเป็นการสร้าง brand loyalty ให้กับผลิตภัณฑ์ของตัวเอง ตัวอย่างเช่น1 asterisk (asterisknow, asteriskpbx — asterisk เป็นผลิตภัณฑ์ IP-PBX ที่เป็น opensource), hp (มีทั้ง hpnews และ hpdirect), Microsoft (Microsoft, Office, SharePoint, msdn, …), TechNet Magazine (TechNetTips), Oracle (Oracle, OracleDatabase, oraclemix, …), IBM (ibmdesign, ibmcognos, ibmstorage, IBMSWNewsletter, LotusTechInfo, LotusKnows, OpenIBM, db2, …), P&G (PGNewsUS, …), Testco Lotus (tescolotus–เทสโก้โลตัสประเทศไทย), Carrefour (carrefournews, …) เป็นต้น

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

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

สำหรับการเขียนโปรแกรมเพื่อติดต่อกับทวิตเตอร์นั้นเราสามารถใช้ Twitter API ซึ่ง API ตัวนี้มีการออกแบบโดยใช้หลักการของ REST (REST –Representational State Tranfer) ซึ่งการทำงานนั้นจะดำเนินการผ่าน HTTP โดยที่ไคลเอนต์ หรือโปรแกรมที่เราสร้างขึ้น จะส่ง request ในรูปแบบของ XML message ไปยังทวิตเตอร์เซอร์ฟเวอร์ และเซอร์ฟเวอร์ก็จะส่ง response กลับมายังไคลเอนต์ในรูปแบบ XML message เช่นกัน ซึ่งใน response message จะประกอบไปด้วยข้อความที่ทวีตและข้อมูลอื่นๆ (เช่น ผู้ส่งหรือ screen name, วัน-เวลาที่ส่ง เป็นต้น) จะเห็นได้ว่า ด้วย Twitter API เราสามารถเขียนโปรแกรมเพื่ออ่านและส่งทวีตระหว่างโปรแกรมของเราและทวิตเตอร์เซอร์ฟเวอร์ผ่าน HTTP ได้ แต่ว่าเราต้องเขียนโปรแกรมเพื่อสร้าง XML message สำหรับการส่ง request และอ่านข้อมูลจาก response message ที่ตอบกลับมาจากทวิตเตอร์เซอร์ฟเวอร์เอาเอง ซึ่งเป็นงานที่หนักพอสมควร โดยเฉพาะสำหรับผมที่ไม่ค่อยจะคุ้นกับการสร้างและอ่านข้อมูลในรูปแบบของ XML เท่าไรนัก

แต่…    ครับ แต่… เหมือนพระเจ้ามาโปรดเลยครับ เพราะว่าขั้นตอนยุ่งยากในการจัดการกับข้อความรูปแบบ XML ด้วยตัวเองนั้นไม่จำเป็นอีกต่อไป เนื่องจากเรามี Twitter API Library สำหรับภาษาโปรแกรมต่างๆ หรือสำหรับเฟรมเวอร์กต่าง ที่ถูกสร้างโดยชุมชนนักพัฒนามากมาย ทำให้ปัจจุบันนี้เราสามารถเขียนโปรแกรมเพื่อติดต่อกับทวิตเตอร์ได้อย่างง่ายดาย และในบทความนี้ ผมจะขอแนะนำ Twitterizer ซึ่งเป็น Twitter API Library ตัวหนึ่ง บน .NET เฟรมเวอร์ก และเป็น API Library ที่ใช้งานง่าย เหมาะสำหรับหรับนักพัฒนา ASP.NET มือใหม่หัดขับอย่างเราๆ ที่จะพัฒนาเว็บไซต์ให้เริ่ดหรูดูมีชาติตระกูลขึ้นมาได้ ที่สำคัญเจ้า Twitterizer นี้แจกฟรี และเป็น opensource API Library ซึ่ง โค้ดของ library เองอยู่ภายใต้ New BSD License ครับ

มาเริ่มกันเลยครับ เริ่มต้นด้วยการดาวน์โหลด Twitterizer .NET API Library (ณ ขณะที่เขียนบทความนี้อยู่ ไลบรารี่ตัวอยู่เป็นรุ่น 1.0.1.149) โดยไปที่เว็บไซต์ http://code.google.com/p/twitterizer และดาวน์โหลดมาได้เลยครับ ไฟล์ไม่ใหญ่มากครับ ขนาดประมาณแค่ 26 KB เท่านั้นเอง เมื่อดาวน์โหลดเสร็จแล้วก็จัดการแตกไฟล์ออกมา ซึ่งเราจะได้ไฟล์มาสองไฟล์คือ Twitterizer.Framework.dll และ Twitterizer.Framework.pdb

โม้มากไปนิด หมดพื้นที่เสียแล้วครับ ผมไม่อยากเขียนบทความให้ยาวมากๆ เพราะจะอ่านลำบาก โดยเฉพาะต่อจากนี้จะเป็นโค้ดและการอธิบายโค้ดด้วย สงสัยคงต้องมีต่อภาคสอง ภาคสามแหงๆ เลยครับ สำหรับท้ายบทความตอนที่ 1 นี้ จะขอนำรูปภาพหน้าจอของโปรแกรมมาใหดูเป็นการยั่วกิเลสกันก่อนสักหน่อยล่ะครับ

myTwitter  

CREDIT : Scott Mitchell, “Integrating Twitter Into An ASP.NET Website”, http://www.4guysfromrolla.com/articles/021710-1.aspx

การตรวจสอบข้อมูลชนิด DateTime และ Numeric ด้วย IsDate() และ IsNumeric() ในภาษา C#


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

ปัญหาที่ว่านี้ผมคิดว่าน่าจะเป็นปัญหาลำดับต้นๆปัญหาหนึ่งสำหรับนักพัฒนาที่เคยพัฒนาโปรแกรมด้วยภาษา VB มาก่อนและมาเริ่มต้นศึกษาการเขียนโปรแกรมด้วยภาษา C# ก็คือ การตรวจสอบชนิดของข้อมูล DateTime กับ Numeric ซึ่งใน VB จะมีฟังก์ชั่นสำหรับตรวจสอบชนิดของข้อมูลทั้งสองนี้และคืนค่ากลับมาเป็น Boolean (True/False) ฟังก์ชั่นที่กล่าวถึงนี้คือ IsDate() และ IsNumeric() ฟังก์ชั่นทั้งสองนี้มีใน VB มานานมากแล้วตั้งแต่สมัย VB4-VB5 นู่น (เก่ากว่านั้นผมไม่ทันครับ ;P) แต่…ใน C# ไม่ยักมี ดังนั้นเวลาที่เราต้องการแปลงชนิดข้อมูลไป-มาก็มักจะเกิดปัญหาบ่อยๆ จากการที่ไม่ได้ตรวจสอบชนิดของข้อมูลเสียก่อน

ที่ว่ามันกวนใจก็คือ เวลาจะแปลงชนิดข้อมูลแต่ละครั้งต้องมาเขียนตรวจสอบเหมือนเดิมๆทุกครั้ง บ่อยเข้าก็ชักจะหงุดหงิด เลยเกิดความคิดว่าน่าจะหาอะไรมาใช้แทนฟังก์ชั่นทั้งสองนั้นใน C# ได้มั่งนะ หาไปหามาก็ไปพบบทความของฝรั่งเค้า ซึ่งผมเห็นว่าน่าสนใจดี ที่เขียนชุดคำสั่งเลียนแบบการทำงานของ IsDate() และ IsNumeric() และผมก็ได้นำแนวคิดของเขาและโปรแกรมตัวอย่างมาลองเขียนและปรับปรุงนิดหน่อย และทดสอบดูแล้วเห็นว่าเข้าท่าดี ก็เลยเอามาแชร์กัน

สำหรับการเขียนฟังก์ชั่นเลียนแบบ IsDate() และ IsNumeric() นี้เรามีพระเอกอยู่หลายตัวครับ พระเอกของเราตัวแรกก็คือเมธอด Parse เมธอดนี้จะทำการแปลงค่า string ที่ส่งเข้ามาให้เป็นชนิดข้อมูลพื้นฐานของ .Net Framwork ซึ่งข้อมูลชนิดพื้นฐานทุกชนิดจะ implement เมธอดนี้ เช่น DateTime.Parse(args), Int32.Parse(args) เป็นต้น เมธอด Parse จะคืนค่าเป็นชนิดของข้อมูลที่เราต้องการหากค่า string ที่ส่งเข้ามานั้น มีรูปแบบที่ถูกต้องตามแบบของชนิดข้อมูลที่เราต้องการแปลง และจะโยน exception ออกมาถ้าหากรูปแบบไม่ถูกต้อง เช่น Int32.Parse(“1234”) จะคืนค่าออกมาเป็น 1234 แต่ Int32.Parse(“ABCD”) กรณีนี้จะเกิด exception ครับ ดังนั้นหลักการก็คือ เราดัก exception ด้วยการใส่บล็อก try {} catch{} เข้าไปที่ฟังก์ชั่นที่เราสร้างขึ้นนั่นเอง เมื่อเกิด exception ก็คืนค่าเป็น false กลับมา หากไม่เกิด exception ก็อนุมานว่าค่าที่ส่งเข้าไปนั้นถูกต้อง และคืนค่า true กลับมา มาดูโค้ดกันดีกว่าครับ โค้ดเราสั้นๆ ง่ายๆ ดังต่อไปนี้

IsDate()
public static bool IsDate(object argo) {
    try {
        DateTime dt = DateTime.Parse(argo.ToString());
        if (dt != DateTime.MinValue && dt != DateTime.MaxValue)
            return true;
        return false;
    } catch {
        return false;
    }
}

IsNumeric()
public static bool IsNumeric(object argo) {
    try {
        float result = float.Parse(argo.ToString());
        return true;
    } catch {
        return false;
    }
}

ฟังก์ชั่นด้านบนทั้งสองฟังก์ชั่น สามารถใช้ได้ใน .Net Framework ตั้งแต่ 1.1 ขึ้นไปเลย เพราะเมธอด Parse นี่มีมาในเวอร์ชั่น 1.1 แล้ว ส่วนผู้ที่ไม่ได้ใช้เฟรมเวอร์กเวอร์ชั่น 1.1 แล้ว และไม่คิดว่าจะกลับไปใช้อีก ก็สามารถใช้ความสามารถที่เพิ่มเติมมาในเฟรมเวอร์กเวอร์ชั่น 2.0 ด้วยการใช้เมธอด TryParse ครับ

เมธอด TryParse นี้เป็นการปรับปรุงให้ดีขึ้นกว่าเมธอด Parse ครับ เพราะมันจะไม่เกิด exception ในกรณีที่แปลงค่าไม่ได้ ซึ่งจะทำให้ประสิทธิภาพโดยรวมของระบบดีขึ้น ทำงานได้เร็วขึ้น เพราะไม่ต้องเสียทรัพยากรของระบบในการจัดการกับ exception เลย เมธอด TryParse นี้จะคืนค่ากลับเป็น Boolean โดยจะมีค่าเป็น false หากแปลงค่าไม่ได้ และเป็น true หากแปลงค่าได้สำเร็จ และในกรณีที่แปลงค่าได้สำเร็จ ค่าที่แปลงได้จะถูกคืนกลับมาในอาร์กิวเม้นต์ตัวที่สอง ที่เราใส่คีย์เวิร์ด out ไว้ข้างหน้านั่นเอง

โค้ดตัวอย่างในการใช้งานทั่วๆไปของเมธอด TryParse
namespace ConsoleApplication1 {
    class Program {
        static void Main(string[] args) {
            DateTime birthDate;
            string dateString = "11/05/1987 23:59:59";
            if (DateTime.TryParse(dateString, out birthDate)) {
                Console.WriteLine("Your birthdate is {0:dd/MM/yyyy hh:mm:ss tt}", birthDate);
            } else {
                Console.WriteLine("Your birthdate is not specified!!!");
            }
            Console.ReadKey();
        }
    }
}
ผลลัพธ์ : Your birthdate is 11/05/1987 11:59:59 PM

 

โค้ดตัวอย่างข้างล่างนี้เป็นการนำเมธอด TryParse มาใช้แทนเมธอด Parse ในฟังก์ชั่น IsDate() และ IsNumeric() ที่เราสร้างขึ้นเองครับ

IsDate()
public static bool IsDate(object argo) {
    DateTime dt;
    if (DateTime.TryParse(argo.ToString(), out dt))
        return true;
    return false;
}

IsNumeric()
public static bool IsNumeric(object argo) {
    float number;
    if (float.TryParse(argo.ToString(), out number))
        return true;
    return false;
}

เท่านี้เราก็ได้ฟังก์ชั่นตรวจสอบชนิดของข้อมูลมาใช้โดยไม่ต้องทิ้งความรู้สึกเดิมๆในตอนที่เขียนด้วย VB ไปแล้วครับ

 

ยังมีอีกวิธีหนึ่งที่ง่ายกว่าเขียนฟังก์ชั่นเลียนแบบการทำงานของ IsDate() และ IsNumeric() เองเสียอีกครับ นั่นคือการเรียกใช้ฟังก์ชั่นเหล่านี้ตรงๆ

ครับ!ไม่ผิดหรอก เราสามารถเรียกใช้ฟังก์ชั่น IsDate(), IsNumeric() และฟังก์ชั่นอื่นๆ ของ VB ได้โดยตรงจาก C# โดย
1. จากโปรเจกต์ของเรา Add Reference ไปยังแอสเซมบลี Microsoft.VisualBasic.dll
2. เพียงเท่านี้เราก็สามารถเข้าถึงเมธอดต่างๆของคลาส Microsoft.VisualBasic.Information ได้แล้วครับ รวมไปถึง IsDate() และ IsNumeric()

ตัวอย่าง:
using Microsoft.VisualBasic;
.
.
.
DateTime? birthDate= (Information.IsDate(args) ? DateTime.Parse(args) : null);

โอ้! พระเจ้า! จอร์จ! มันง่ายอะไรอย่างนี้! แต่ว่า . . . ดูก่อน! ท่านผู้เจริญ! ข่าวร้ายครับ จากแหล่งข้อมูลอ้างอิงของเรา วิธีนี้ไม่เป็นที่แนะนำ เพราะว่า คลาสต่างๆในเนมสเปซ Microsoft.VisualBasic (ใน Microsoft.VisualBasic.dll) นั้น เขาทำขึ้นมาเพื่อให้มันเข้ากันได้กับโค้ดภาษา VB รุ่นเก่าๆ (VB4-VB6) เท่านั้นครับ  ดังนั้นในอนาคตอันไกล อาจจะไม่มีการสนับสนุนการเข้ากันได้กับโค้ดภาษา VB รุ่นเก่าๆเหล่านั้น (เมื่อมันกลายเป็นภาษารุ่นทวดของทวดของทวด) ก็เป็นได้ เราจึงควรจะใช้ฟังก์ชันใหม่ เมธอดใหม่ที่มีให้ใช้ในเฟรมเวอร์กรุ่นใหม่ๆจะดีกว่า

 

แหล่งข้อมูลอ้างอิง :

การทำ Paging สำหรับ DataList Control และ Control ประเภท Data-bound Control ทั้งหลาย โดยใช้ PagedDataSource ตอนที่ 2


สำหรับคราวนี้จะเป็น การพัฒนาเพิ่มเติมจากบทความคราวก่อนนะครับ โดยจะเพิ่มปุ่ม Back และ Next เข้าไป แล้วนำ DropDownList Control มาแทรกไว้ตรงกลาง โดยกำหนดคุณสมบัติของปุ่มที่เพิ่มเติมขึ้นมาดังนี้

หากเป็นหน้าแรก ปุ่ม Back จะถูก Disable หากเป็นหน้าสุดท้าย ปุ่ม Next จะถูก Disable หากข้อมูลมีการแสดงผลให้หน้าเดียว ปุ่ม Back และ Next จะถูก Disable พร้อมกัน เมื่อกดปุ่ม Back จะแสดงข้อมูลย้อนหลังไป 1 หน้า และเมื่อกดปุ่ม Next จะแสดงข้อมูลหน้าถัดไป ส่วนการเลือกดูข้อมูลที่หน้าใดๆก็จะสามารถเลือกจาก DropDownList Control เหมือนกับในบทความคราวก่อน

มาเริ่มกันเลย สำหรับบทความคราวนี้ ขออนุญาตนำแต่โค้ดภาษา C# มาแสดงอย่างเดียวนะครับ เพื่อไม่ให้บทความยืดยาวเกินเหตุ

ครั้งนี้มีการปรับเปลี่ยนตัวแปร currentPageIndex ให้เป็น property ของ Page และเก็บค่าไว้ใน ViewState นะครับ เพื่อให้จำหน้าปัจจุบันได้ จะได้สามารถเลื่อนหน้าไปมาได้
private int currentPageIndex { get { return (int)ViewState["currentPage"]; } set { ViewState["currentPage"] = value; } }

ในฟังก์ชั่น BindControl() เพิ่มการตรวจสอบหน้าแรกหรือหน้าสุดท้าย โดยใช้ property "IsFirstPage" และ "IsLastPage" ของคลาส PagedDataSource มาตรวจสอบ (บรรทัดที่โค้ดตัวหนา)
private void BindControl() {
        // …
        // อ่านข้อมูลจากฐานข้อมูล มาใส่ไว้ใน DataTable
        // …

        PagedDataSource pgNdx = new PagedDataSource();
        pgNdx.DataSource = dv;          // Bind DataView ให้กับ PageDataSource object
        pgNdx.PageSize = 5;               // กำหนดจำนวนรายการที่แสดงในแต่ละหน้า
        pgNdx.AllowPaging = true;       // กำหนดว่าให้มีการทำ paging ได้
        ddlPageIndex.Items.Clear();     // เพิ่มจำนวนหน้าลงใน DropDownList Control
        for (int i = 0; i <= (pgNdx.PageCount – 1); i++) {
            ddlPageIndex.Items.Add(new ListItem(Convert.ToString(i + 1), Convert.ToString(i + 1)));
        }
        ddlPageIndex.SelectedIndex = currentPageIndex;
        pgNdx.CurrentPageIndex = currentPageIndex;
        btnGoBack.Enabled = !pgNdx.IsFirstPage;         // ถ้าหากเป็นหน้าแรกให้ disable ปุ่ม Back
        btnGoNext.Enabled = !pgNdx.IsLastPage;         // ถ้าหากเป็นหน้าสุดท้ายให้ disable ปุ่ม Next
        DataList1.DataSource = pgNdx;
        DataList1.DataBind();
}
จากนั้นมาจัดการกับการเปลี่ยนหน้าเมื่อมีการกดปุ่ม Back และ Next
void btnGoBack_Click(object sender, EventArgs e) {
        currentPageIndex -= 1;
        BindControl();
}
void btnGoNext_Click(object sender, EventArgs e) {
        currentPageIndex += 1;
        BindControl();
}
เรียบร้อยครับ มาดูผลงานสักหน่อย

การทำ Paging สำหรับ DataList Control และ Control ประเภท Data-bound Control ทั้งหลาย โดยใช้ PagedDataSource


ครั้งนี้เป็นครั้งแรกที่เขียนเรื่องราวออกแนววิชาการครับ ท่านที่เคยแวะเวียนเข้ามาอ่านมาก่อนอาจจะสงสัย ว่าเอ… หมอนี่มันมีสาระเป็นด้วยหรือนี่ ก็อย่าได้แปลกใจอะไรไปเลย ที่ผมเขียนขึ้นเรื่องนี้ขึ้นมาก็เพื่อเก็บไว้สำหรับตัวเองจะได้ค้นหาวิธีการต่างๆในการพัฒนางานได้สะดวกขึ้น เพราะงานที่ทำๆไว้ไม่เคยได้เอามารวบรวม เวลาจะทำอะไรคล้ายๆกันก็ดันจำไม่ได้ บางทีเพื่อเรื่องเดิมๆต้องเสียเวลาหาเสียหลายวัน ซึ่งเป็นการเสียเวลาโดยใช่เหตุ
 
ปกติผมไม่ค่อยจะได้ใช้งาน DataList Control บ่อยนัก อาจจะเพราะไม่ถนัด หรือใช้ GridView บ่อยกว่า (แต่ก็ยังไม่เชี่ยวนะครับ) ทำให้เวลานำมาใช้งานแต่ละครั้งก็เกิดความลำบากไม่น้อย เมื่อต้องการที่จะจัดหน้าให้กับมัน เนื่องด้วยเจ้า Control ตัวนี้(และตัวอื่นๆในตระกูล Data-bound Control) ไม่มี Property ที่เกี่ยวกับการจัดหน้า เช่น AllowPaging, PageSize, etc. มาให้ เหมือนใน GridView ดังนั้นจึงต้องหาศัยผู้ช่วย ซึ่งเจ้าคลาส PagedDataSource นี่แหละครับคือฮีโร่สำหรับงานนี้
 
คลาส PagedDataSource นี้จะอยู่ในเนมสเปซ System.Web.UI.WebControls ซึ่งอยู่ในแอสเซมบลี System.Web (ใน System.Web.dll) อีกที เจ้าคลาส PagedDataSource ตัวนี้ เป็นคลาสที่รวบรวมนำเอา property ต่างๆ ที่เกี่ยวข้องกับการแสดงผลแบบที่แบ่งเป็นหน้า มาไว้ใช้สำหรับ Control ประเภท Data-bound Control ทั้งหลาย เช่น DataList, Detail View, Form View,… รวมไปถึงเจ้า DataGrid และ GridView ด้วย พูดง่ายๆก็คือเจ้า PagedDataSource ตัวนี้ จะช่วยให้ Control ประเภท Data-bound Control เหล่านี้ สามารถแสดงผลในรูปแบบที่แบ่งเป็นหน้าๆ ได้นั่นเอง (สำหรับรายละเอียดต่างๆ ของ PagedDataSource นี่ สามารถไปดูได้ที่ msdn นะครับ)
 
ตัวอย่างการทำ paging สำหรับ DataList โดยใช้ DropDownList Control เป็นตัวเลือกแต่ละหน้า
1. สร้าง instance object ของ PagedDataSource และกำหนด Bind ข้อมูลเข้ากับ objec PagedDataSource C#
C#

private void BindControl() {
        // …
        // อ่านข้อมูลจากฐานข้อมูล มาใส่ไว้ใน DataTable
        // …
        PagedDataSource pgNdx = new PagedDataSource();
        pgNdx.DataSource = dv;      // Bind DataView ให้กับ PageDataSource object
        pgNdx.PageSize = 5;           // กำหนดจำนวนรายการที่แสดงในแต่ละหน้า
        pgNdx.AllowPaging = true;  // กำหนดว่าให้มีการทำ paging ได้

        ddlPageIndex.Items.Clear();  // เพิ่มจำนวนหน้าลงใน DropDownList Control
        for (int i = 0; i <= (pgNdx.PageCount – 1); i++) {
            ddlPageIndex.Items.Add(new ListItem(Convert.ToString(i + 1), Convert.ToString(i + 1)));
        }
        ddlPageIndex.SelectedIndex = currentPageIndex;   // currentPageIndex เป็น global variable ซึ่งถูกกำหนดไว้ก่อนหน้า
        pgNdx.CurrentPageIndex = currentPageIndex;

        DataList1.DataSource = pgNdx;
        DataList1.DataBind();
}

VB

Private Sub BindControl()
        ‘– …
        ‘– อ่านข้อมูลจากฐานข้อมูล มาใส่ไว้ใน DataTable
        ‘– …
        Dim pgNdx As New PagedDataSource()
        pgNdx.DataSource = dv      ‘– Bind DataView ให้กับ PageDataSource object
        pgNdx.PageSize = 5           ‘– กำหนดจำนวนรายการที่แสดงในแต่ละหน้า
        pgNdx.AllowPaging = True  ‘– กำหนดว่าให้มีการทำ paging ได้

        ddlPageIndex.Items.Clear()  ‘– เพิ่มจำนวนหน้าลงใน DropDownList Control
        For i As Integer = 0 To (pgNdx.PageCount – 1)
            ddlPageIndex.Items.Add(New ListItem(Convert.ToString(i + 1), Convert.ToString(i + 1)))
        Next
        ddlPageIndex.SelectedIndex = currentPageIndex    ‘– currentPageIndex เป็น global variable ซึ่งถูกกำหนดไว้ก่อนหน้า
        pgNdx.CurrentPageIndex = currentPageIndex

        DataList1.DataSource = pgNdx
        DataList1.DataBind()
End Sub

2. กำหนดการจัดการเมื่อมีการเปลี่ยนหน้าโดยการเลือกจาก DropDownList Control
C#

void ddlPageIndex_SelectedIndexChanged(object sender, EventArgs e) {
        currentPageIndex = Convert.ToInt32(ddlPageIndex.SelectedValue) – 1;
        BindControl();
}

VB

Protected Sub ddlPageIndex_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ddlPageIndex.SelectedIndexChanged
        currentPageIndex = CInt(ddlPageIndex.SelectedValue) – 1
        BindControl()
End Sub

เท่านี้ก็เรียบร้อยครับ สามารถจัดแบ่งหน้าให้กับ Control DataList ได้แล้ว

หมายเหตุ DropDownList Control "ddlPageIndex" จะต้องกำหนด property AutoPostBack="true" เอาไว้ด้วย เพื่อจะได้จัดการเมื่อมีอีเว้นต์ SelectedIndexChanged เกิดขึ้นจะทำการ refresh เว็บเพจทันที ซึ่งหากนำไปใช้ร่วมกับ ASP.Net Ajax UpdatePanel ก็จะทำให้การแสดงผลได้เนียนขึ้น ไม่กระเพื่อม