Month: July 2015

  • มาทำความรู้จักกับ Validator ใน ASP.NET กันเถอะ

                ในการพัฒนาโปรแกรมโดยทั่วไป สิ่งหนึ่งที่นักพัฒนาควรคำนึงถึงและให้ความสำคัญในการรับค่าข้อมูลจากผู้ใช้ คือ การตรวจสอบความถูกต้องของข้อมูลที่รับเข้า เพื่อให้มั่นใจว่าข้อมูลที่ได้มาจะเป็นประโยชน์ สามารถนำไปใช้ในการประมวลผลต่อไปได้ และลดปัญหาการเก็บข้อมูลขยะไว้ในฐานข้อมูลซึ่งอาจทำให้ฐานข้อมูลมีขนาดใหญ่เกินความจำเป็น อีกทั้งยังถือเป็นการป้องกันความผิดพลาดที่อาจจะเกิดขึ้นจากการเก็บข้อมูลที่ไม่ถูกต้อง ในกรณีเลวร้ายอาจมีผลกระทบทำให้ฐานข้อมูลเกิดความเสียหายได้ ดังนั้น การตรวจสอบความถูกต้องของข้อมูลก่อนบันทึกถือเป็นสิ่งหนึ่งที่นับว่ามีความสำคัญสำหรับนักพัฒนาที่จะต้องคำนึงถึงในการเก็บข้อมูลจากผู้ใช้
                วิธีที่ใช้ในการตรวจสอบสามารถทำได้หลายวิธี ซึ่งเดิมผู้พัฒนาจะต้องเขียน Client-Script (อาจจะเป็น JavaScript VBScript หรือ JQuery) เพื่อใช้ในการตรวจสอบเองทั้งหมด โดยวิธีการนี้ผู้พัฒนาจะต้องมีความรู้เกี่ยวกับ Client Script เหล่านั้นพอสมควร และอาจต้องใช้เวลานานในกรณีที่มีการตรวจสอบที่ซับซ้อน แต่นับว่าเป็นโชคดีของนักพัฒนาที่ใช้เครื่องมือ ASP.NET ในการพัฒนาโปรแกรม เนื่องจาก .NET framework ได้จัดเตรียมเครื่องมือในการตรวจสอบเหล่านี้ไว้ให้เรียบร้อยแล้วตั้งแต่เวอร์ชั่น Visual Studio .NET 2003 เพื่ออำนวยความสะดวกให้กับผู้พัฒนาสามารถหยิบมาใช้ได้โดยง่าย ทำให้การตรวจสอบไม่ใช่เรื่องยากและซับซ้อนอีกต่อไป และยังถือเป็นการประหยัดเวลา ไม่จำเป็นต้องเขียนสคริปต์ตรวจสอบเองทั้งหมด เพียงกำหนด properties ต่างๆที่จำเป็นให้ validator เหล่านั้นและเลือกใช้ให้เหมาะสมกับความต้องการก็จะสามารถตรวจสอบความถูกต้องของข้อมูลได้โดยง่ายดาย ผู้เขียนจึงเห็นว่าการทำความเข้าใจกับความสามารถของ validator เหล่านี้ถือเป็นสิ่งสำคัญเพื่อช่วยในการตัดสินใจเลือก validator มาใช้ให้เหมาะสมกับงานและความต้องการในการตรวจสอบนั้นๆ
                หากแบ่ง Validator control ที่มีใน ASP.NET ตามลักษณะการทำงาน สามารถแบ่งออกได้เป็น 2 ลักษณะ ดังนี้

    การตรวจสอบข้อมูลในฝั่ง Client โดยการตรวจสอบข้อมูลในลักษณะนี้ จะเกิดขึ้นทันทีเมื่อผู้ใช้มีการป้อนข้อมูลเข้ามาและการตอบโต้นี้จะยังไม่มีการส่งค่าไปยังฝั่ง server ซึ่งข้อดีของการตรวจสอบในลักษณะนี้ คือ สามารถโต้ตอบกับผู้ใช้ในเวลาอันรวดเร็วและแสดงให้ผู้ใช้ทราบได้ทันทีว่าเกิดข้อผิดพลาดในการป้อนข้อมูล โดยไม่ต้องรอให้มีการเรียกใช้ไปยังฝั่งเซิร์ฟเวอร์ก่อนจึงจะตอบสนองกลับมายังผู้ใช้ และยังถือเป็นการลดจำนวนครั้งในเรียกใช้ไปยังฝั่งเซิร์ฟเวอร์โดยไม่จำเป็น ซึ่งหลักการทำงานของ Validator ของ ASP.NET ในลักษณะนี้ คือ Validator จะทำหน้าที่แปลง Validation เป็น JavaScript และถูกทำงานที่ฝั่ง Client ซึ่งจะขึ้นอยู่กับการทำงานของ Validation Control แต่ละประเภทที่ใช้นั่นเอง
    การตรวจสอบข้อมูลในฝั่งเซิร์ฟเวอร์ โดยการตรวจสอบในลักษณะนี้ จะเกิดขึ้นที่ฝั่งเซิร์ฟเวอร์ ซึ่งมีข้อดี คือ สามารถเพิ่มความปลอดภัยและความแม่นยำในการตรวจสอบอีกระดับก่อนจะบันทึกข้อมูลเหล่านั้นลงฐานข้อมูลในกรณีที่อาจมีข้อมูลผิดพลาดที่ตกสำรวจมาจากการตรวจสอบในฝั่ง Client โดยการตรวจสอบในลักษณะนี้ ผู้พัฒนาจะเป็นผู้เขียนโค้ดในการตรวจสอบตามเงื่อนไขที่กำหนดขึ้นเอง ซึ่ง ASP.NET ก็ได้มีการเตรียม validation control เพื่อรองรับการตรวจสอบในลักษณะนี้ไว้แล้วเช่นกัน

    โดย Validation control ที่มีเตรียมไว้ใน ASP.NET ประกอบด้วย Validator ชนิดต่างๆ ดังนี้
    • RequiredFieldValidator
    • RegularExpressionValidator
    • RangeValidator
    • CompareValidator
    • CustomValidator
    • Validation Summary

                เพื่อให้ง่ายต่อการทำความเข้าใจ ผู้เขียนจะขอพูดถึงการกำหนดค่า Properties ให้กับ validator หลักๆที่สำคัญที่ทุกตัวต้องมีไว้เป็นเบื้องต้น และจะเพิ่ม properties เพิ่มเติมที่แตกต่างจาก properties หลักของ validator แต่ละตัวดังนี้

    ID : เป็นการกำหนดชื่อ ID ให้กับตัว validator ซึ่งผู้เขียนแนะนำให้ตั้งชื่อให้สื่อความหมาย เพื่อง่ายต่อการต่อยอดในการพัฒนาร่วมกับผู้อื่น
    ControlToValidate : เป็นการกำหนดว่าจะให้ validator ดังกล่าวทำการควบคุมและตรวจสอบ control หรือ element ตัวใดในหน้าจอ
    Display : เป็นการกำหนดลักษณะในการแสดงผลของ validator ซึ่งมีด้วยกัน 3 แบบคือ

    o Static : แบบจองพื้นที่ในการแสดงผล validator กรณีมีข้อผิดพลาด แม้ไม่พบข้อผิดพลาด validator ก็จะยังคงจองพื้นที่ส่วนนั้นไว้เช่นกัน
    o Dynamic : จะแสดงผล validator เมื่อพบข้อผิดพลาด และเมื่อมีการแก้ไขข้อผิดพลาดดังกล่าวแล้ว Error message ของ validator ตัวดังกล่าวจะหายไปและลดพื้นที่ส่วนการแสดงผลให้เหมือนก่อนจะพบข้อผิดพลาด
    o None : ไม่แสดงผลบนหน้าจอ

    Error Message : เป็นการกำหนดข้อความที่ต้องการให้แสดง เมื่อผู้ใช้กรอกข้อมูลผิดพลาด ซึ่งถือเป็นการชี้แนะให้ผู้ใช้ทราบว่าความผิดพลาดดังกล่าวเกิดขึ้นจากสาเหตุใด และควรแก้ไขอย่างไร
    SetFocusOnError : เป็นการกำหนด Focus ให้กับ control ที่พบความผิดพลาด แต่หากในหน้าจอดังกล่าวพบข้อผิดพลาดหลายจุดและ validator ทุกตัวมีการกำหนดค่า SetFocusOnError เป็น true จะทำให้ Focus เลื่อนไปยังจุดที่มีข้อผิดพลาดจุดแรกที่พบทันที
    Text : เป็นการกำหนดในส่วนที่จะแสดงผล เมื่อ validator พบข้อผิดพลาดนั่นเอง ซึ่งโดยทั่วไปแล้วมักกำหนดให้แสดงเป็นเครื่องหมายดอกจันท์ หรือ * และวางไว้หลัง control ตัวที่ validator ดังกล่าวกำลังควบคุม เพื่อแจ้งให้ผู้ใช้ทราบว่าข้อมูลที่กรอกส่วนใดกำลังมีปัญหาหรือพบข้อผิดพลาดจากการตรวจสอบอยู่นั่นเอง
    ToolTip : เป็นการกำหนดข้อความที่ต้องการให้แสดงเมื่อผู้ใช้นำเมาส์ไปชี้ที่ validator ที่กำลังแสดงข้อผิดพลาดอยู่
    Validation group : เป็นการจัดกลุ่มให้กับ validator ที่ใช้ในการตรวจสอบ ซึ่งโดยปกติหากไม่กำหนดค่าในส่วนนี้จะถือว่า control ทั้งหมดในหน้าจอถูกจัดกลุ่มการควบคุมไว้เป็นกลุ่มเดียวกันทั้งหน้าจอ แต่หากมีบางกรณีที่ต้องการแยกกลุ่มในการตรวจสอบ ต้องมีการระบุ ValidationGroup ของปุ่มและ validator ที่ต้องการตรวจสอบเหล่านั้นให้เป็นกลุ่มเดียวกัน ซึ่งจะทำให้ validator ตัวอื่นที่ไม่ใช่กลุ่มดังกล่าวไม่ถูกนำมาตรวจสอบ เพราะถือว่าเป็นการตรวจสอบคนละส่วนกัน

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

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

    • InitialValue : ใช้เปรียบเทียบค่าจาก InitialValue ที่กำหนดใน validator กับค่าที่ผู้ใช้กรอกมาใน control ที่ validator ตัวนี้ควบคุมอยู่ ซึ่งโดยทั่วไปการใช้งาน RequiredFieldValidator อาจไม่จำเป็นต้องกำหนดค่าให้กับ  properties นี้ แต่ผู้เขียนจะขอยกตัวอย่างเพื่อให้ผู้พัฒนาเห็นภาพการทำงานของลักษณะการกำหนดค่า InitialValue  เพื่อนำไปประยุกต์ใช้งานได้ ดังนี้

    ตัวอย่างที่ 1 การเรียกใช้งาน RequiredFieldValidator  แบบทั่วไป(ไม่ได้กำหนดค่า InitialValue )

    <asp:TextBox ID="TxtEmail" runat="server"></asp:TextBox>
    <asp:RequiredFieldValidator ID="ReqEmail" runat="server"
    ErrorMessage="Please enter your email-address" 
    ControlToValidate="TxtEmail" SetFocusOnError="True">*
    </asp:RequiredFieldValidator>

    ตัวอย่างที่ 2  เช่น กรณีที่มีการกำหนดค่า InitialValue และมีการเลือกประเภทจาก dropdownlist ที่มีชื่อว่า DdlType และบังคับเลือก

    <asp:DropDownList ID="DdlType" runat="server"> 
    <asp:ListItem Value="--Select--">--Select--</asp:ListItem>
    <asp:ListItem Value="Item1" />
    <asp:ListItem Value="Item2" />
    <asp:ListItem Value="Item3" />
    </asp:DropDownList>
    <asp:RequiredFieldValidator ID="ReqType" runat="server"
    ErrorMessage="Please select type" ControlToValidate="DdlType" 
    SetFocusOnError="True" InitialValue="--Select--" >*
    </asp:RequiredFieldValidator>

    จากตัวอย่างที่ 2 จะเห็นว่า ค่า InitialValue คือ “–Select–” นั่นหมายถึงว่า หากผู้ใช้เลือกรายการ “–Select–” จาก dropdownlist แล้วกดปุ่มบันทึก validator ดังกล่าวจะแสดงข้อผิดพลาดทันที

    RegularExpressionValidator

                เป็น validator ที่ใช้ในการตรวจสอบรูปแบบการกรอกของข้อมูล เช่น อีเมล์ หมายเลขโทรศัพท์ URL ของเว็บไซต์ หรือรหัสไปรษณีย์ เป็นต้น โดย properties  ที่สำคัญเพิ่มเติมจากที่กล่าวไว้แล้วในข้างต้นของ validator นี้คือ

    • ValidationExpression ซึ่งทาง .NET ได้มีการกำหนดรูปแบบ regular expression สำเร็จรูปในการตรวจสอบไว้ให้แล้วในเบื้องต้น แต่ผู้พัฒนาสามารถประยุกต์ใช้ และปรับแก้ให้รูปแบบของ regular expression ที่ใช้ในการตรวจสอบเป็นไปในแบบที่ต้องการได้

    ตัวอย่าง การใช้งาน ValidationExpression ในการตรวจสอบรูปแบบ URL ของเว็บไซต์

    <asp:TextBox ID="txtURL" runat="server"></asp:TextBox>
    <asp:RegularExpressionValidator ID="RegExURL" runat="server"
    ControlToValidate="txtURL" ErrorMessage="Internet URL 's format is incorrect" SetFocusOnError="True" ValidationExpression="http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&amp;=]*)?">*</asp:RegularExpressionValidator>

    จากตัวอย่าง พบว่า regular expression ที่ใช้ในการตรวจสอบรูปแบบของข้อมูล คือ  http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&amp;=]*)? ซึ่งเป็นแบบสำเร็จรูปที่ ASP.NET ได้เตรียมไว้ให้แล้ว

    RangeValidator

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

    • MaximumValue : เป็นการกำหนดค่าสูงสุดที่สามารถกรอกได้
    • MinimumValue : เป็นการกำหนดค่าข้อมูลต่ำสุดที่สามารถกรอกได้
    • Type :เป็นการกำหนดชนิดของข้อมูลที่จะทำการตรวจสอบช่วงของข้อมูลว่าให้มองเป็นชนิดใด โดยชนิดของข้อมูลประกอบด้วย
      • String : การตรวจสอบช่วงข้อมูลชนิดที่เป็นชนิด String นี้จะคำนวณค่าโดยเทียบกับ Ascii Code (http://www.lookuptables.com/)
      • Integer
      • Double
      • Date

    ตัวอย่างที่ 1 : การตรวจสอบช่วงของข้อมูลที่เป็นชนิด string

    <asp:DropDownList ID="DdlChoice" runat="server">
    
    <asp:ListItem Value="--Select--">--Select--</asp:ListItem>
    <asp:ListItem Value="A" >A</asp:ListItem>
    <asp:ListItem Value="B" >B</asp:ListItem>
    <asp:ListItem Value="C" >C</asp:ListItem>
    <asp:ListItem Value="D">D</asp:ListItem>
    <asp:ListItem Value="E">E</asp:ListItem>
    </asp:DropDownList>
    <asp:RangeValidator ID="RangeChoice" runat="server"
    ControlToValidate="DdlChoice" 
    ErrorMessage="Please select between A-D"
    MaximumValue="D" MinimumValue="A">*</asp:RangeValidator>

    จากตัวอย่างจะพบข้อผิดพลาดหากผู้ใช้เลือกรายการ “E” เนื่องจากเมื่อนำค่าดังกล่าวไปเปรียบเทียบกับค่าแบบ Ascii code แล้วจะมีค่าเกินช่วงที่กำหนดใน validator คือ A-D นั่นเอง

    ตัวอย่างที่ 2 : การตรวจสอบช่วงของข้อมูลที่เป็นชนิดตัวเลข

    Enter number (between 1 - 10) :
    <asp:TextBox ID="txtAmount" runat="server"></asp:TextBox>
    <asp:RangeValidator ID="RangeNumber" runat="server"
    ControlToValidate="txtAmount" 
    ErrorMessage="The data must be from 1 to 10"
    MaximumValue="10" MinimumValue="1" Type="Integer">*</asp:RangeValidator>

    CompareValidator

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

    • ValueToCompare : เป็น properties ที่ใช้ในกรณีที่ต้องการเปรียบเทียบค่าที่รับจากผู้ใช้กับค่าคงที่ที่ระบุ
    • ControlToCompare : เป็น properties ที่ใช้กำหนดคอนโทรลตัวที่ต้องการเปรียบเทียบค่า(ในกรณีที่มีการเปรียบเทียบค่าจาก 2 คอนโทรล)
    • Operator :เป็นpropertiesที่ใช้ในการกำหนดการปฏิบัติการในการเปรียบเทียบค่า มีดังนี้
      • Equal : ค่าของข้อมูลที่รับมาต้องมีค่าเท่ากันกับค่าที่ต้องการเปรียบเทียบ
      • NotEqual : ค่าของข้อมูลที่รับมาต้องไม่เท่ากับค่าที่ต้องการเปรียบเทียบ
      • GreaterThan : ค่าของข้อมูลที่รับมาต้องมีค่ามากกว่าค่าที่ต้องการเปรียบเทียบ
      • GreaterThanEqual : ค่าของข้อมูลที่รับมาต้องมีค่ามากกว่าหรือเท่ากับค่าที่ต้องการเปรียบเทียบ
      • LessThan : ค่าของข้อมูลที่รับมาต้องมีค่าน้อยกว่าค่าที่ต้องการเปรียบเทียบ
      • LessThanEqual : ค่าของข้อมูลที่รับมาต้องมีค่าน้อยกว่าหรือเท่ากับค่าที่ต้องการเปรียบเทียบ
      • DataTypeCheck : เป็นการระบุการตรวจสอบชนิดของข้อมูล และทำงานร่วมกับ properties ที่ชื่อว่า Type โดยการกำหนด properties นี้ จะส่งผลให้ค่าที่ถูกกำหนดไว้ให้กับ properties ที่มีชื่อว่า ValueToCompare และ ControlToCompare ไม่ทำงาน
    • Type : ชนิดของข้อมูลที่ต้องการตรวจสอบ
    หมายเหตุ : ค่าที่ต้องการเปรียบเทียบอาจเป็นค่าที่มาจากคอนโทรลอีกตัวที่ต้องการเปรียบเทียบ(ControlToCompare) หรือมาจากค่าที่กำหนดไว้ใน ValueToCompare นั่นเอง ซึ่งค่า properties ทั้งสองนี้ไม่ควรกำหนดร่วมกัน ควรเลือกใช้เพียงตัวใดตัวหนึ่งเท่านั้น แต่หากมีการกำหนดทั้ง 2 ค่าพร้อมกัน การทำงานของ ControlToCompare จะมีลำดับในการทำงานก่อน


    ตัวอย่างที่
    1
    การเปรียบเทียบค่าข้อมูล 2 ค่าจากคอนโทรล เช่น กรณีการพิมพ์รหัสผ่านและยืนยันรหัสผ่าน เป็นต้น

    Password :<asp:TextBox ID="txtPassword" runat="server">
    </asp:TextBox><br />
    Retype-password :<asp:TextBox ID="txtConfirmPassword" 
    runat="server"></asp:TextBox> 
    <asp:CompareValidator ID="CmpPassword" runat="server" 
    ErrorMessage="Password must be the same" 
    ControlToCompare="txtPassword" ControlToValidate="txtConfirmPassword">*</asp:CompareValidator>
    
    

    ตัวอย่างที่ 2 การเปรียบเทียบค่าของข้อมูลกับค่าคงที่ที่กำหนด กรณีที่ต้องกรอกข้อมูลที่มีค่ามากกว่าหรือเท่ากับ 18

    Age :<asp:TextBox ID="txtAge" runat="server"></asp:TextBox>
    <asp:CompareValidator ID="CmpAge" runat="server" 
    ControlToValidate="txtAge" 
    ErrorMessage="Age must greater than or equal 18 years old"
    Operator="GreaterThanEqual" ValueToCompare="18">*
    </asp:CompareValidator>
    
    

    ตัวอย่างที่ 3 การตรวจสอบชนิดของข้อมูล กรณีกรอกข้อมูลราคาต้องเป็นตัวเลขเท่านั้น

    Price : <asp:TextBox ID="txtPrice" runat="server"></asp:TextBox>
    
    <asp:CompareValidator ID="CmpType" runat="server" 
    ControlToValidate="txtPrice" ErrorMessage="Price must be number" 
    Operator="DataTypeCheck" Type="Double">*</asp:CompareValidator>

    CustomValidator

                หากการตรวจสอบด้วย validator ที่กล่าวมาก่อนหน้านี้ ยังไม่ครอบคลุมการตรวจสอบที่ต้องการ นักพัฒนาสามารถกำหนดเงื่อนไขในการตรวจสอบ และการทำงานนอกเหนือจากที่ validator ที่ ASP.NET เตรียมไว้ให้ขึ้นได้เอง โดยใช้ validator ประเภท CustomValidator ซึ่ง validator ประเภทนี้ จะมีช่องทางในการตรวจสอบสำหรับผู้พัฒนาเตรียมไว้ให้ทั้ง 2 ฝั่ง คือทั้งฝั่ง client และฝั่ง server โดยมี properties ที่จำเป็นเพิ่มเติมจาก properties หลัก ดังนี้

    • ClientValidationFunction : เป็นการกำหนดค่าของฟังก์ชั่นในฝั่ง client ที่ใช้ในการตรวจสอบข้อมูล
    • OnServerValidate : เป็นการกำหนดฟังก์ชั่น event หรือเมธอดที่ใช้ในการตรวจสอบข้อมูลในฝั่งเซิร์ฟเวอร์

    ตัวอย่างที่ 1 การใช้งาน custom validator ในการตรวจสอบค่าข้อมูลจากฝั่ง client

    <script type="text/javascript">
    function CheckData(oSrc, args) {
    if(args.Value.length >= 5 && args.Value.search('-') == -1)
    args.IsValid = true;
    else
    args.IsValid = false;
    oSrc.innerText = "(Your custom message here) ";
    }
    </script>
    
    <asp:TextBox ID="txtUserName" runat="server"></asp:TextBox>
    <asp:CustomValidator ID="CustomUsername" runat="server" 
    ClientValidationFunction="CheckData" ControlToValidate="txtUserName" 
    ErrorMessage="Username must be greater than or equal 5 letters and cannot contain contain '-'">*</asp:CustomValidator>
    
    หมายเหตุ : หากต้องการเปลี่ยนแปลงข้อความผิดพลาดที่ต้องการแสดงสามารถทำได้โดยกำหนด      oSrc.innerText ในฟังก์ชั่น JavaScript นั้น

    ตัวอย่างที่ 2 การใช้งาน custom validator ในการตรวจสอบค่าข้อมูลจากทั้งฝั่ง client และฝั่งเซิร์ฟเวอร์

    ฝั่ง Client

    <script type="text/javascript">
    function CheckData(oSrc, args) {
    if(args.Value.length >= 5 && args.Value.search('-') == -1)
    args.IsValid = true;
    else
    args.IsValid = false;
    
    </script>
    <asp:TextBox ID="txtUserName" runat="server"></asp:TextBox>
    <asp:CustomValidator ID="CustomUsername" runat="server"
    ClientValidationFunction="CheckData" 
    ControlToValidate="txtUserName"
    ErrorMessage="Username must greater than or equal 5 letters and cannot contain '-' " onservervalidate="CustomUsername_ServerValidate">*
    </asp:CustomValidator>
    
    

    ฝั่งเซิร์ฟเวอร์

    protected void CustomUsername_ServerValidate(object source, ServerValidateEventArgs args)
    {
    string username = args.Value;
    string[] Users = {"Amanda","Robert","John","Jennie"};
    if (Users.Contains(username))
    {
    args.IsValid = false;
    
    CustomUsername.ErrorMessage = "Username is already exists in database.";
    }
    else
    args.IsValid = true;
    }
    

                จากตัวอย่างจะมีการตรวจสอบค่าข้อมูลรหัสผู้ใช้จากฝั่ง client ก่อน ว่าต้องมีความยาวตั้งแต่ 5 ตัวอักขระขึ้นไปและต้องไม่ประกอบด้วย “-” หากมีเงื่อนไขครบตามกำหนดจะทำการตรวจสอบอีกครั้งในฝั่งเซิร์ฟเวอร์ว่าจะต้องไม่ซ้ำกับค่าที่มีอยู่แล้วจากข้อมูลรหัสผู้ใช้สมมติที่มีอยู่ และหากพบข้อผิดพลาดจะมีการแสดงข้อความแจ้งบอก

    Validation Summary

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

    • DisplayMode :เป็นรูปแบบในการแสดงผลสรุปรวมข้อผิดพลาด ซึ่งประกอบด้วย
      • List : เป็นการแสดงผลแบบเว้นบรรทัด
      • BulletList : เป็นการแสดงผลแบบ bullet ซึ่งโดยปกติจะมีค่าตั้งต้นเป็นการแสดงผลในรูปแบบนี้
      • SingleParagraph : เป็นการแสดงผลข้อผิดพลาดแบบเว้นวรรคต่อกันในบรรทัดเดียวกันไปเรื่อยๆ

    ตัวอย่างผลลัพธ์การแสดงผลของ DisplayMode ในแต่ละแบบ

    DisplayMode

    • HeaderText : เป็นการระบุข้อความที่ต้องการให้แสดงในส่วนบนของข้อสรุปผิดพลาดทั้งหมดที่เกิดขึ้น
    • ShowMessageBox : เป็นการกำหนดว่าต้องการให้แสดงผลสรุปในรูป MessageBox หรือไม่ ซึ่ง properties ดังกล่าวจะไปทำการสร้างฟังก์ชั่นที่เรียกใช้งาน alert() ของ JavaScript เพื่อการแสดงผลสรุปข้อผิดพลาดนี้
    • ShowSummary : เป็นการแสดงผลรายการข้อผิดพลาดในรูปแบบ HTML ในตำแหน่งที่ validator ตัวนี้ถูกวางอยู่

    ตัวอย่างที่ 1 การใช้ ValidationSummary ในการสรุปข้อผิดพลาดในหน้าจอโดยแสดงผลในรูปแบบ MessageBox

    Username : <asp:TextBox ID="txtUserName" runat="server">
    </asp:TextBox>
    <asp:CustomValidator ID="CustomUsername" runat="server" 
    ClientValidationFunction="CheckData" ControlToValidate="txtUserName" 
    ErrorMessage="Username must greater than or equal 5 letters and cannot contain '-' "  onservervalidate="CustomUsername_ServerValidate">*
    </asp:CustomValidator><br />
    Password :
    <asp:TextBox ID="txtPass" runat="server"></asp:TextBox>
    <asp:RequiredFieldValidator ID="ReqPass" runat="server" 
    ControlToValidate="txtPass" ErrorMessage="Password">*
    </asp:RequiredFieldValidator>
    <asp:ValidationSummary ID="ValidationSummary" runat="server"
    HeaderText="Errors:" ShowMessageBox="True" />
    
    

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

    แหล่งข้อมูลอ้างอิง :
    http://www.codeproject.com/Articles/3882/ASP-NET-Validators-Unclouded
    http://www.codeproject.com/Articles/334310/Understanding-ASP-NET-Validation-Techniques
    http://www.codeproject.com/Articles/7943/Validator-Controls-in-ASP-NET

  • รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่ (ตอนที่ 1)

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

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

         ก่อนที่จะเข้าสู่รายละเอียดเรามาดูกันก่อนว่าภาพรวมทั้งหมดแล้วเกี่ยวกับอะไรบ้าง
    ________• การจัดวางเครื่องมือและองค์ประกอบต่างๆ
    ________• ส่วนตอบสนองกับผู้ใช้
    ________• การนำเสนอและอำนวยความสะดวกกับผู้ใช้

    แนวคิดที่ 1 : Try A One Column Layout instead of multicolumns.
    _____การจัดรูปแบบบทความให้มีเพียงคอลัมน์เดียวจะช่วยทำให้เราสามารถควบคุมความต่อเนื่องของบทความได้ดี ช่วยอำนวยความสะดวกและสามารถกำหนดทิศทางการอ่านบทความของผู้อ่านได้อย่างแม่นยำ เนื่องจากมีเพียงการเลื่อนขึ้นและลงเท่านั้น ในขณะที่การจัดบทความแบบหลายคอลัมน์จะทำให้ผู้อ่านเกิดความสับสน ส่งผลให้ผู้อ่านเสียสมาธิหรือหมดความสนใจในบทความดังกล่าวได้idea001

    แนวคิดที่ 2 : Try Distinct Clickable/Selected Styles instead of blurring them.
    _____ในการออกแบบหน้าจอโดยเฉพาะส่วนของ links, buttons สิ่งที่กำลังถูกเลือก(chosen items) และข้อความ(text)หรือบทความ(content) ควรออกแบบให้ไปในรูปแบบเดียวกันหมดทุกๆหน้าจอ เพื่อช่วยให้ผู้ใช้งานไม่สับสนหรือต้องทำความเข้าใจเพิ่มเติมในรูปแบบพื้นฐานที่ได้ออกแบบไว้ ดังตัวอย่างภาพทางด้านซ้าย โดยผู้ออกแบบเลือกสีฟ้าแทนในส่วนของ links, buttonsและสีดำแทนส่วนที่กำลังถูกเลือก(chosen items) และสีเทาแทนข้อความโดยในแต่ละองค์ประกอบใช้รูปแบบเดียวกันภายในองค์ประกอบนั้น ส่วนในภาพทางด้านขวา เป็นการเลือกสีและรูปแบบที่หลากหลายในองค์ประกอบเดียวกันซึ่งจะส่งผลให้ผู้ใช้สับสนกับหน้าจอดังกล่าวได้idea006

    แนวคิดที่ 3 : Try More Contrast instead of similarity.
    _____การเพิ่มความน่าสนใจหรือการยกระดับความคมชัดในส่วนขององค์ประกอบสำคัญๆส่งผลให้เกิดความแตกต่างจากองค์ประกอบรวมอื่นๆในหน้าจอจะเป็นการยกระดับ UI ของคุณให้มีประสิทธ์ภาพมากขึ้น ไม่ว่าจะเป็นการใช้โทนสีที่เข้มขึ้น การไล่เฉดสีหรือการใส่เงาให้กับองค์ประกอบนั้นๆทำให้ผู้ใช้งานรับรู้ถึงองค์ประกอบสำคัญนั้นได้ทันทีจากการเข้าใช้งาน ช่วยให้ผู้ใช้งานสะดวกและเข้าใจการทำงานของหน้าจอได้ง่ายยิ่งขึ้นidea011

    แนวคิดที่ 4 : Try Fewer Borders instead of wasting attention.
    _____การจัดรูปแบบองค์ประกอบโดยใช้เส้นเป็นอีกสิ่งหนึ่งที่มีการนำมาใช้เพื่อเพิ่มจุดน่าสนใจให้กับตัวUI ทั้งยังสามารถนำมาจัดหรือแบ่งขอบเขตของกลุ่มองค์ประกอบในหน้าจอได้อย่างชัดเจน จนบางครั้งนักออกแบบก็ใช้งานการจัดองค์ประกอบแบบนี้มากจนเกินจำเป็นไปในแต่ละส่วนของหน้าจอส่งผลให้กลุ่มองค์ประกอบนั้นถูกตัดขาดออกจากกันอย่างสิ้นเชิงและทำให้การควบคุมทิศทางของหน้าจอผิดจากที่ได้ตั้งเอาไว้ ดังนั้นการเลือกใช้เส้น ควรใช้แค่พอจำเป็นจนไม่ทำให้หน้าจอดูรกจนเกินไป เราอาจจะใช้วิธีอื่นๆมาช่วยในการจัดกลุ่มองค์ประกอบได้ ไม่ว่าจะใช้ช่องว่างระหว่างกลุ่มองค์ประกอบ การเน้นตัวอักษรหรือสีเป็นต้นidea023

    แนวคิดที่ 5 : Try Designing For Zero Data instead of just data heavy cases.
    _____โดยทั่วไปแล้วเรามักจะออกแบบหน้าจอให้รองรับกับการแสดงข้อมูล ไม่ว่าเป็น 1, 10, 100 หรือเป็น 1000 ข้อมูลโดยบางทีเราอาจลืมออกแบบสำหรับกรณีที่ข้อมูลเป็น 0 ส่งผลให้เวลาแสดงหน้าจอ อาจเป็นหน้าจอว่างๆหรือมีการแจ้งเตือนว่าไม่พบรายการหรือข้อมูล โดยสำหรับนักออกแบบแล้วอาจคิดว่าไม่ส่งผลกระทบใดๆกับหน้าจอมากนัก แต่สำหรับผู้ใช้งานระบบที่เจอหน้าจอที่ว่างเปล่าแล้วอาจเกิดข้อสงสัยได้ว่าเกิดอะไรขึ้นหรือเกิดความสับสนว่าจะทำอะไรในขั้นตอนต่อไป ดังนั้นการออกแบบในส่วนของกรณีที่ไม่พบข้อมูลหรือรายการ อาจใส่ข้อความอธิบายถึงสาเหตุที่ทำให้ไม่พบข้อมูลหรือแนะนำขั้นตอนที่จะทำให้เกิดข้อมูลต่างๆได้ ส่งผลให้ผู้ใช้ไม่สะดุดและสะดวกกับการใช้งานระบบได้มากยิ่งขึ้นidea025

    แนวคิดที่ 6 : Try Conventions instead of reinventing the wheel.
    _____การสื่อสารกับผู้ใช้ถือเป็นอีกส่วนที่มีความสำคัญในการออกแบบหน้าจอ ซึ่งในการออกแบบนั้น เราควรออกแบบให้สอดคล้องกับการใช้งานของผู้ใช้ระบบหรือความเคยชินที่ผู้ใช้เคยได้ทำมาโดยตลอด ส่งผลให้หน้าจอที่ได้ออกแบบไว้ตอบสนองความต้องการและลดเวลาในการเรียนรู้หน้าจอเพิ่มเติม ซึ่งโดยทั่วไปแล้วจะมีรูปแบบหลักๆอยู่พอสมควร เช่นการให้มีปุ้มปิดหน้าจอมุมบนขวา ปุ่มกดถัดไปอยุ่ด้านขวาและย้อนกลับอยู่ด้านซ้าย สัญลักษณ์รูปเฟืองสื่อถึงการตั้งค่า เป็นต้นidea029

    แนวคิดที่ 7 : Try Bigger Click Areas instead of tiny ones.
    _____จากหัวข้อที่ 3 นี้ก็เป็นอีกแนวคิดหนึ่งที่จะเพิ่มความน่าสนใจให้กับองค์ประกอบประเภท links, buttons ได้ คือการเพิ่มขยายหรือขอบเขตในการกดองค์ประกอบนั้นๆ เพราะในปัจจุบัน หน้าจอที่ได้ออกแบบไว้ถูกนำไปใช้งานในอุปกรณ์ที่หลากหลายมากขึ้นการออกแบบให้สิ่งเหล่านี้มีขนาดที่เหมาะสมในหน้าจอหนึ่ง อาจจะไม่สะดวกที่จะใช้งานในอีกหน้าจอหนึ่ง หรือการออกแบบให้ปุ่มกดหรือลิงค์เล็กจนเกินไป อาจส่งผลให้ผู้ใช้ไม่สะดวกกับการหาหรือกดสิ่งเหล่านั้นได้การขยายขนาดหรือขอบเขตของการกดจะช่วยให้ผู้ใช้สะดวกมากอีกขึ้น และยังมีวิธีการเพิ่มข้อความให้มีความยาวมากขึ้น หรือใช้ไอคอนร่วมกับข้อความ เป็นต้นidea038

    แนวคิดที่ 8 : Try Icon Labels instead of opening for interpretation.
    _____ถ้าพุดถึงเรื่องของไอคอนแล้ว ไอคอนมีส่วนช่วยให้หน้าจอของเราดูดีขึ้นได้และยังทำให้ผู้ใช้งานสามารถเข้าใจถึงการทำงานของไอคอนนั้นได้เกือบทันที แต่ในบางครั้งกลุ่มผู้ใช้งานบางกลุ่ม อาจจะไม่สามารถตีความหมายของไอคอนตามวัตถุประสงค์การใช้งานที่เราได้ออกแบบเอาไว้ หรือไอคอนที่เรานำมาใช้ อาจไม่แสดงความหมายได้คลุมเครือ ดังนั้นวิธีที่จะช่วยให้ไอคอนสามารถแสดงวัตถุได้อย่างชัดเจนคือการเพิ่มข้อความควบคู่ไปกับตัวไอคอนด้วย จะทำให้ผู้ใช้งานหน้าจอเข้าใจได้ทันทีและไม่สับสนกับความหมายที่จะสื่อถึง และบางกรณีไอคอนที่นำมาใช้อาจเล็กหรือสีที่ใช้ดูกลมกลืนไปกับองค์ประกอบอื่นๆ การใส่ข้อความจึงเป็นการช่วยให้ไอคอนดูคมชัดมากขึ้นidea047

    แนวคิดที่ 9 : Try Natural Language instead of dry text.
    _____แนวคิดข้อนี้ออกจะแปลกตาสำหรับผู้เขียนสักหน่อย เพราะเป็นการนำภาษาธรรมชาติ (ภาษาพูด)มาใช้เป็นคำอธิบายแทนการใช้คำทางการหรือราชการที่ปัจจุบันเราใช้กันอย่างแพร่หลาย ซึ่งการนำภาษาธรรมชาติมาใช้ช่วยเขียนคำชี้แจ้ง จะทำให้ผู้ใช้เข้าใจถึงจุดหมายที่ผู้ใช้จะต้องกระทำกับหน้าจอ แต่ในเว็บไซต์ที่ใช้งานในเชิงราชการ อาจดูไม่ค่อยเหมาะสมหรือไม่เป็นที่ชอบใจของผู้ใช้งานได้ ข้อนี้จึงขึ้นอยู่กับว่าเราจะไปใช้ในลักษณะไหน มากน้อยเพียงไหนขึ้นอยุ่กับกลุ่มผู้ใช้งานระบบด้วย แต่อาจนำมาใช้ผสมกับคำที่เป็นทางการในบางจุดได้ เพื่อให้ผู้ใช้งานเข้าใจมากขึ้นและไม่ดูน่าเกลียดจนเกินไป แต่ในอนาคตอาจการเป็นที่นิยมแทนการใช้คำทางราชการก็เป็นได้idea048

    แนวคิดที่ 10 : Try Extra Padding instead of overcrowding elements.
    _____ช่องว่างสำคัญไฉน เมื่อพูดถึงช่องว่างนักออกแบบบางท่านอาจบอกว่าไม่ค่อยสำคัญมากนัก แต่จริงๆแล้วช่องว่างก็เป็นส่วนหนึ่งที่จะทำให้หน้าจอเราดูสะอาดตามากขึ้น และสามารถนำช่องว่างมาใช้สำหรับแยกกลุ่มองค์ประกอบได้ นอกจากการใช้เส้นแล้ว เราสามารถนำช่องว่างมาแยกข้อความในตารางให้รับรู้ได้ง่ายยิ่งขึ้นด้วย เพราะบางกรณีที่มีการแสดงผลแบบตาราง จะมีการนำข้อมูลจำนวนมากมาแสดงให้ผู้ใช้งานรับรู้ แต่กลับไม่ได้ออกแบบส่วนของการแบ่งแยกขอบเขตของcolumn หรือ row ไว้เลย ส่งผลให้ข้อมูลที่นำมาแสดงอาจติดกันยาวเหยียดจนผู้ใช้สับสนกับจุดสิ้นสุดของข้อมูลได้ การเพิ่มช่องว่างก็เป็นอีกวิธีที่สามารถนำมาใช้ได้ หรือเราอาจนำมาใช้ควบคู่กับเส้นก็เป็นอีกวิธีที่ดีเช่นกันidea063


    สำหรับบทความชุด “รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่” ตอนที่ 1 ขอจบที่ 10 ข้อแรกติดตามตอนที่ 2 ได้ตามลิงค์ด้านล่างเลยครับ

    รวมเทคนิคการออกแบบ UI ให้สวยงามสำหรับ Designer มือใหม่ (ตอนที่ 2)

    ขอบคุณครับ

  • อย่าตกเป็นเหยื่อของ Clickbait (เว็บไซต์หลอกให้คลิก)

    เดี๋ยวนี้จะเห็นบน Facebook มีการแชร์เนื้อหาจากเว็บไซต์ต่างๆ แล้วโปรยหัวข้อข่าวให้แบบว่า น่าคลิกมาก อยากอ่านเนื้อหาต่อ จนทำให้คนต้องคลิกไปอ่าน พวกนี้เรียกว่า “Clickbait” — bait แปลว่า เหยื่อ

    และบางเว็บ ก็ช่างหน้าไม่อาย เอาเนื้อหาเก่ามานำเสนอ เพื่อให้คนคลิกไม่พอ ยังแอบอ้างว่า ผลงานการหาข่าวเป็นของตัวเองอีกต่างหาก เช่น

    http://www.bigza.com/news-175102

    1

     

    เนื้อหาบอกว่าเป็นการเขียนว่า ข่าววันที่ 9 ก.ค 58 แถม “ผู้สื่อข่าว” BigZa อีกต่างหาก (แล้วมาเลี่ยงภายหลังว่ารับข่าวจาก Social Media)

    2

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

    7

     

     

    พวกนี้ มันทำอย่างนี้ ทำไม ???? ตอบ เพราะทุกครั้งที่เรา “คลิก” อ่าน มันจะได้อันนี้ … โฆษณา …

     

    3

    เอาหล่ะ แล้วจะตรวจสอบอย่างไร ว่า เป็นข่าวจริงหรือไม่ บน Google Chrome สมัยนี้ สามารถคลิกขวาที่ภาพ แล้ว เลือก “Search Google for this image”

     

     

    4

    ผลที่ได้คือ ภาพข่าว และ รายละเอียดว่า เป็นข่าวที่เผยแพร่มาแล้ว เมื่อไหร่

    5

    เมื่อลองคลิกเข้าไปในสำนักข่าวที่น่าเชื่อถือ ก็พบว่า ข่าวดังกล่าว เกิดขึ้นตั้งแต่ 25 เมษายน 58

     

     

     

    6

     

    เรียนมาเพื่อพิจารณา …

  • How to reset root password CentOS 7.1

    • เข้า Single user mode โดย reboot แล้วเมื่อได้เมนูของ Grub ให้เลื่อนแถบสีไปยัง Kernel ที่ต้องการบูต (โดยปกติจะถูกเลือกไว้อยู่แล้ว) ให้กด e
      reset1จะได้หน้าจอดังนี้
      reset2สิ่งที่เราสนใจคือบรรทัดที่ขึ้นต้นว่า linux ซึ่งในบทความนี้คือ linux16 สำหรับ CentOS 7/7.1 x86_64 บนเมนบอร์ดที่ใช้ระบบ BIOS (อาจจะพบกับ linuxefi สำหรับเมนบอร์ดที่ใช้ระบบ UEFI) เมื่อหาเจอแล้วเลื่อน cursor ไปที่ ข้อความ ro
      reset2-1เปลี่ยน ro เป็น rw init=/sysroot/bin/sh
      reset3-1กดปุ่ม ctrl และปุ่ม x พร้อมกันเพื่อบูตระบบจะได้ดังภาพ
      reset4
    • พิมพ์คำสั่ง chroot  /sysroot
      reset5-1
    • พิมพ์ passwd เพื่อเปลี่ยนรหัสผ่านสำหรับ root
    • สร้างแฟ้ม autorelabel เพื่อปรับปรุงกฏของ selinux (ถึงแม้จะไม่ได้ใช้งาน selinux ก็ตาม เพื่อความไม่ประมาท) โดยคำสั่ง touch /.autorelabel
    • พิมพ์ exit เพื่อยกเลิก chroot
    • พิมพ์ reboot
      reset6-1
    • ระบบจะรีบูตสองรอบ อัตโนมัติเพื่อปรับปรุง selinux และไฟล์ autorelabel จะถูกลบอัตโนมัติ
    • ล็อคอินเข้าระบบด้วยผู้ใช้ root และ password ที่เปลี่ยนไป ลบแฟ้ม /.bash_history ทิ้งด้วยคำสั่ง rm /.bash_history (ถูกสร้างตอนออกจากระบบ chroot)
    • จบขอให้สนุกครับ

    อ้างอิงเพิ่มเติม
    https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sec-Terminal_Menu_Editing_During_Boot.html#sec-Recovering_Root_Password

  • ทำอย่างไรให้สามารถกำหนดจุดพิกัดบนแผนที่ Google map แบบจุดเดียวและหลายจุดจากฐานข้อมูลได้ด้วย ASP.NET C#

          การพัฒนาเว็บไซต์ในปัจจุบัน พบว่ามีบางเว็บไซต์มีความต้องการในการแสดงผลตำแหน่ง ที่ตั้งบนแผนที่ Google map เพื่ออำนวยความสะดวกให้กับผู้เยี่ยมชมเว็บไซต์ในการค้นหาตำแหน่งที่ตั้งของสถานที่นั้นๆมากกว่าการบอกเพียงที่อยู่อย่างเช่นแต่ก่อน อาธิเช่น เว็บไซต์ที่เป็นศูนย์รวมในการจองที่พัก ที่มีความจำเป็นต้องแสดงที่ตั้งของโรงแรมที่มีในบริเวณหรือละแวกนั้นๆที่เข้ามาร่วมให้ข้อมูลกับเว็บไซต์ในการจองที่พัก หรือแม้กระทั่งโรงพยาบาล ห้างสรรพสินค้า โรงเรียน มหาวิทยาลัย ที่เว็บไซต์ต้องการแสดงที่ตั้งเพื่อให้ผู้เยี่ยมชมเว็บไซต์สามารถทราบได้ว่าสถานที่เหล่านั้นมีที่ตั้งอยู่ในบริเวณใดบ้าง เพื่อเป็นประโยชน์ให้ผู้ที่เข้ามาเยี่ยมชมเว็บไซต์สามารถเรียกดูได้จากแผนที่เพื่อศึกษาเส้นทาง หรือหาตำแหน่งที่จะสามารถไปยังจุดนั้นๆได้โดยง่ายและใช้ระยะทางใกล้ที่สุดนั่นเอง
          ในบทความนี้ ผู้เขียนจึงขอพูดถึงวิธีการแสดงผลตำแหน่งที่ตั้งบน Google map ซึ่งมีทั้งแบบกำหนดตายตัว โดยมีการระบุตำแหน่งที่ตั้งทั้งละติจูดและลองจิจูด และแบบที่มีการดึงค่าของละติจูดและลองจิจูดมาจากฐานข้อมูลของเว็บไซต์ที่พัฒนาโดยใช้เครื่องมือ ASP.NET ด้วย C# และแบบที่มีการกำหนดจุดแสดงตำแหน่งเพียงจุดเดียวและหลายจุดพร้อมกัน เพื่อประโยชน์กับนักพัฒนาท่านอื่นๆที่มีความสนใจสามารถนำไปประยุกต์ใช้กับเว็บไซต์ของตนได้

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

    การแสดงผลแบบจุดเดียว

    1. อ้างอิงพาธที่ตั้งของ Google API ซึ่งเป็นส่วนหนึ่งของการแสดงผลบนแผนที่ Google map และไฟล์จาวาสคริปต์ที่ใช้ในการแสดงผล(ถ้ามี)
    <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
     
    <script src="js/mapwithmarker.js" type="text/javascript"></script>
    1. กำหนดสไตล์ชีทที่ใช้ในการแสดงผล เมื่อมีการคลิกตำแหน่งที่ได้ทำการกำหนดพิกัดไว้
    <style type="text/css">  
    .labels { color: black; background-color: #FF8075; font-family: Arial; font-size: 11px; font-weight: bold; text-align: center; width: 12px; }  </style>
    1. กำหนดพิกัดที่ต้องการให้แผนที่ค้นหาจุดกึ่งกลางของการแสดงผล ซึ่งโดยปกติจะถือเอาจุดแรกที่ต้องการแสดงเป็นตำแหน่งกึ่งกลางของการแสดงผลตำแหน่งบนแผนที่นั้นๆ เพื่อให้ตำแหน่งดังกล่าวอยู่กึ่งกลางของแผนที่ที่ต้องการแสดงนั่นเอง
    var mapOptions = {  
    center: new google.maps.LatLng(ค่าละติจูด, ค่าลองจิจูด),  
    zoom: 12, 
    ///ขนาดที่ต้องการให้ซูมเป็นค่าตั้งต้น  
    mapTypeId: google.maps.MapTypeId.ROADMAP  };
    1. กำหนดส่วนที่ต้องการให้แสดงแผนที่ ว่าต้องการให้แสดงในส่วนใดของเว็บไซต์
    var map = new google.maps.Map(document.getElementById("dvMap"), mapOptions);
     ///ในที่นี้พื้นที่ที่ต้องการให้แสดงผลในเว็บไซต์ คือ dvMap โดยนำค่าที่กำหนดกึ่งกลางไว้ในขั้นตอนที่ 3 (mapOptions) มาเป็นค่าพารามิเตอร์ในการแสดงผลด้วย
    
    1. การกำหนดจุดพิกัดที่ต้องการแสดงผล ซึ่งค่าที่ต้องการคือ ชื่อสถานที่ ค่าละติจูด ลองจิจูด และคำอธิบายในการแสดงผลตำแหน่งสถานที่ที่เราทำการกำหนดไว้ ดังนี้
      • กำหนดค่าพิกัดลองจิจูดและละติจูดของจุดที่เราต้องการกำหนดบนแผนที่
      var infoWindow = new google.maps.InfoWindow();
       var myLatlng = new google.maps.LatLng(ค่าละติจูด, ค่าลองจิจูด);
      
      
      • กำหนดค่าพิกัดตำแหน่งของจุดและพารามิเตอร์ต่างๆที่จำเป็นต้องใช้ในการกำหนดจุดที่เราต้องการกำหนดบนแผนที่
      var marker = new MarkerWithLabel({
       position: myLatlng, //เป็นการกำหนดค่าพิกัดตำแหน่งของจุดที่เราต้องการกำหนดบนแผนที่
       map: map, //เป็นการกำหนดพื้นที่ที่ต้องการแสดงแผนที่ ในที่นี้คือ dvMap
       title: title, //เป็นการกำหนดชื่อสถานที่
       labelContent:1,  //เป็นการกำหนดหมายเลขลำดับของตำแหน่งแสดงผล
       labelAnchor: new google.maps.Point(7, 30),
       labelClass: "labels", //เป็นการกำหนดรูปแบบในการแสดงผลด้วยสไตล์ชีท
       labelInBackground: false
       });
      
      
      • กำหนดการแสดงผลเมื่อผู้เยี่ยมชมมีการคลิกบนจุดดังกล่าว
      (function(marker) {
       google.maps.event.addListener(marker, "click", function(e) {
       infoWindow.setContent(description);
       //เป็นการกำหนดข้อความที่ต้องการแสดง เมื่อผู้เยี่ยมชมเว็บไซต์คลิกบนจุดดังกล่าว
       infoWindow.open(map, marker);
       });
       })(marker);
      
      
    1. สร้างพื้นที่ที่กำหนดการแสดงผลในส่วน body
    <div id="dvMap" style="width: 800px; height: 700px;">
     </div>
    1. แสดง code ทั้งหมดที่ใช้
    <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
     <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     <html xmlns="http://www.w3.org/1999/xhtml">
     <head runat="server">
     <title>Google map Test for one point</title>
     <style type="text/css">
     .labels { color: black; background-color: #FF8075; font-family: Arial; font-size: 11px; font-weight: bold; text-align: center; width: 12px; }
     </style>
     <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
     <script src="js/mapwithmarker.js" type="text/javascript"></script>
     <script type="text/javascript">
     window.onload = function() {
     var mapOptions = {
     center: new google.maps.LatLng(7.006923, 100.500238),
     zoom: 12,
     mapTypeId: google.maps.MapTypeId.ROADMAP
     };
     var map = new google.maps.Map(document.getElementById("dvMap"), mapOptions);
     var infoWindow = new google.maps.InfoWindow();
     var myLatlng = new google.maps.LatLng(7.006923, 100.500238);
     var marker = new MarkerWithLabel({
     position: myLatlng,
     map: map,
     title: 'มหาวิทยาลัยสงขลานครินทร์',
     labelContent: 1,
     labelAnchor: new google.maps.Point(7, 30),
     labelClass: "labels", // the CSS class for the label
     labelInBackground: false
     });
     (function(marker ) {
     google.maps.event.addListener(marker, "click", function(e) {
     infoWindow.setContent('มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตหาดใหญ่');
     infoWindow.open(map, marker);
     });
     })(marker );
     }
     </script>
     </head>
     <body>
     <form id="form1" runat="server">
     <div id="dvMap" style="width: 800px; height: 700px;">
     </div>
     </form>
     </body>
     </html>

    ตัวอย่างภาพผลลัพธ์ที่ได้ :
    Map1point

    แบบหลายจุดและดึงค่าละติจูด ลองจิจูดจากฐานข้อมูลมาแสดงผล

    โดยลักษณะการเขียนจะคล้ายๆกับแบบกำหนดจุดเพียงจุดเดียวอย่างที่กล่าวไว้แล้วในตอนต้น แต่จะแตกต่างกันในส่วนของการดึงข้อมูล ซึ่งจะเน้นเฉพาะส่วนที่แตกต่าง และแสดง code สรุปรวมให้ดูอีกครั้ง

    ไฟล์ default.aspx ในฝั่ง Client

    1. กำหนดค่าตัวแปรที่ใช้ในแสดงผลจาก Repeater ซึ่งเป็นเครื่องมือที่มีอยู่แล้วใน .NET โดยตัวแปรที่จะใช้ที่นี้ให้มีชื่อว่า markers และค่าที่ต้องการนำมาใช้จะเป็นฟิลด์ของ Name, Latitude, Longitude และ Description ซึ่งดึงมาจากฐานข้อมูล(โดยชื่อฟิลด์สามารถเปลี่ยนแปลงได้ตามข้อมูลที่มีอยู่จริงในฐานข้อมูลของแต่ละท่าน)
      <script type="text/javascript">
       var markers = [
       <asp:Repeater ID="rptMarkers" runat="server">
       <ItemTemplate>
       {
       "title": '<%# Eval("Name") %>',
       "lat": '<%# Eval("Latitude") %>',
       "lng": '<%# Eval("Longitude") %>',
       "description": '<%# Eval("Description") %>'
       }
       </ItemTemplate>
       <SeparatorTemplate>
       ,
       </SeparatorTemplate>
       </asp:Repeater>
       ];
       </script>
    2. กำหนดพิกัดที่ต้องการให้แผนที่ค้นหาจุดกึ่งกลางของการแสดงผล ซึ่งโดยปกติจะถือเอาจุดแรกที่ต้องการแสดงเป็นตำแหน่งกึ่งกลางของการแสดงผลตำแหน่งบนแผนที่นั้นๆ เพื่อให้ตำแหน่งดังกล่าวอยู่กึ่งกลางของแผนที่ที่ต้องการแสดงนั่นเอง
      var mapOptions = {
       center: new google.maps.LatLng(markers[0].lat, markers[0].lng),
       zoom: 8,
       mapTypeId: google.maps.MapTypeId.ROADMAP};
    3. กำหนดค่าต่างๆ และวนค่าตัวแปร markers ที่ดึงมาจากฐานข้อมูลและตัว Repeater ที่กล่าวไว้ในข้างต้น และทำการกำหนดค่าต่างๆให้กับแต่ละจุดที่ต้องการ โดยรายละเอียดในการกำหนดค่าจะคล้ายกับวิธีกำหนดแบบจุดเดียว(แบบแรก) แต่จะมีการวนซ้ำให้ครบจำนวนตัวแปรที่ดึงมาจากฐานข้อมูล
      var infoWindow = new google.maps.InfoWindow();
       var map = new google.maps.Map(document.getElementById("dvMap"), mapOptions);
       for (i = 0; i < markers.length; i++) {
       //เป็นการวนค่าตัวแปร markers ที่ดึงมาจากฐานข้อมูลและตัว Repeater ที่กล่าวไว้ในข้างต้น
      
        var data = markers[i]
       //นำค่าจากตัวแปร markers  ที่ดึงมาทีละรายการตามลำดับมาใส่ไว้ในตัวแปร data เพื่อนำไปใช้ในการกำหนดค่าต่อไป
      var myLatlng = new google.maps.LatLng(data.lat, data.lng);
       //กำหนดค่าละติจูดและลองจิจูด
      var marker = new MarkerWithLabel({
       position: myLatlng, //เป็นการกำหนดตำแหน่งที่ต้องการแสดงผล
      map: map,
       title: data.title, //เป็นการกำหนดชื่อที่ต้องการแสดงผลเมื่อนำเมาส์ไปชี้ยังจุดดังกล่าว
      labelContent: i+1//เป็นการกำหนดหมายเลขลำดับให้กับจุดดังกล่าว
       labelAnchor: new google.maps.Point(7, 30),
       labelClass: "labels", // the CSS class for the label
       labelInBackground: false}
       );(function (marker, data) {google.maps.event.addListener(marker, "click", function (e) {
       infoWindow.setContent(data.description);
       //เป็นการกำหนดข้อความที่ต้องการแสดง เมื่อผู้เยี่ยมชมเว็บไซต์คลิกบนจุดดังกล่าว
      infoWindow.open(map, marker);
       });
       })(marker, data);
       }
    4. Code ทั้งหมดในฝั่งไฟล์ Default.aspx
      <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
      
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       <html xmlns="http://www.w3.org/1999/xhtml">
       <head runat="server">
       <title></title>
       </head>
       <body>
       <form id="form1" runat="server">
       <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script><script src="js/mapwithmarker.js" type="text/javascript"></script>
      <script type="text/javascript">
       var markers = [
       <asp:Repeater ID="rptMarkers" runat="server">
       <ItemTemplate>
       {
       "title": '<%# Eval("Name") %>',
       "lat": '<%# Eval("Latitude") %>',
       "lng": '<%# Eval("Longitude") %>',
       "description": '<%# Eval("Description") %>'
       }
       </ItemTemplate>
       <SeparatorTemplate>
       ,
       </SeparatorTemplate>
       </asp:Repeater>
       ];
       </script>
       <script type="text/javascript">
       window.onload = function() {
       var mapOptions = {
       center: new google.maps.LatLng(markers[0].lat, markers[0].lng),
       zoom: 8,
       mapTypeId: google.maps.MapTypeId.ROADMAP
       };
       var infoWindow = new google.maps.InfoWindow();
       var map = new google.maps.Map(document.getElementById("dvMap"), mapOptions);
       var j = 1;
       for (i = 0 ; i <= markers.length-1; i++) {
       var data = markers[i]
       var myLatlng = new google.maps.LatLng(data.lat, data.lng);
       // var marker = new google.maps.Marker({
       var marker = new MarkerWithLabel({
       position: myLatlng,
       map: map,
       title: data.title,
       labelContent: i+1,
       labelAnchor: new google.maps.Point(7, 30),
       labelClass: "labels", // the CSS class for the label
       labelInBackground: false
       });
       (function(marker, data) {
       google.maps.event.addListener(marker, "click", function(e) {
       infoWindow.setContent(data.description);
       infoWindow.open(map, marker);
       });
       })(marker, data);
       }
       }
       </script>
       <div id="dvMap" style="width: 500px; height: 500px">
       </div>
       </form>
       </body>
       </html>

     

    ไฟล์ default.cs ในฝั่ง server

    using System;
     using System.Collections.Generic;
     using System.Web;
     using System.Web.UI;
     using System.Web.UI.WebControls;
     using System.Data;public partial class _Default : System.Web.UI.Page
     {
     protected void Page_Load(object sender, EventArgs e)
     {
     if (!this.IsPostBack)
     {
     rptMarkers.DataSource = GetData();
    //กำหนดแหล่งข้อมูลให้กับตัว Repeater ที่เราต้องการใข้ในการแสดงผล
     rptMarkers.DataBind();
     }
     }
      private DataTable GetData()
    //เมธอดที่ใช้ในการดึงค่าข้อมูลจากฐานข้อมูล ซึ่งในที่นี้มีการส่งค่ากลับเป็น datatable และมีการสมมุติค่าข้อมูลใน datatable เพื่อให้เห็นภาพการดึงจากฐานข้อมูลเท่านั้น แต่สามารถนำไปประยุกต์ใช้กับการติดต่อฐานข้อมูลจริงได้  {
     DataTable table = new DataTable();
     table.Columns.Add("Name", typeof(string));
     table.Columns.Add("Latitude", typeof(decimal));
     table.Columns.Add("Longitude", typeof(decimal));
     table.Columns.Add("Description", typeof(string));
     table.Rows.Add("มหาวิทยาลัยสงขลานครินทร์", 7.006923, 100.500238, "Hatyai");
     table.Rows.Add("มหาวิทยาลัยราชภัฏ สงขลา", 7.172661, 100.613726, "Songkla");
     return table;
     }
     }
    1. ดึงข้อมูลจากแหล่งข้อมูลที่ต้องการ ซึ่งประกอบด้วยข้อมูลตามที่ต้องการให้แสดงผล เช่น ค่าละติจูด ลองจิจูด และชื่อสถานที่ โดยในกรณีนี้ผู้เขียนขอสมมติค่าและสร้าง datatable ขึ้นมา เพื่อใช้ในการทดสอบ โดยแสดงในเมธอด GetData() หากเป็นข้อมูลที่ใช้จริงผู้พัฒนาสามารถนำไปประยุกต์กับการดึงข้อมูลของท่านได้
    2. กำหนดค่าแหล่งข้อมูลให้กับ repeater เพื่อสร้างตัวแปร marker ตามที่กล่าวไว้ในข้างต้น
    3. ผลลัพธ์ที่ได้ :

    Mapmultipoint

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

    แหล่งข้อมูลอ้างอิง :
    http://www.dotnetbull.com/2013/06/multiple-marker-with-labels-in-google.html
    http://www.codeproject.com/Articles/36151/Show-Your-Data-on-Google-Map-using-C-and-JavaScrip

  • วิดีโอแนะนำการติดตั้ง PSU12-Sritrang Server โปรแกรมสำหรับการจัดการห้องบริการคอมพิวเตอร์ (cloning & control PC)

    วิดีโอแนะนำการติดตั้ง PSU12-Sritrang Server โปรแกรมสำหรับการจัดการห้องบริการคอมพิวเตอร์ (cloning & control PC)
    โดย  Wiboon Warasittichai on youtube

    01 PSU12-sritrang install (ตอนที่ 1 วิธีติดตั้ง)
    PSU12-sritrang-t01
    https://youtu.be/GAhZhGCciY0

    02 PSU12-sritrang cloning (ตอนที่ 2 วิธีโคลนนิ่งฮาร์ดดิสก์)
    PSU12-sritrang-t02
    https://youtu.be/CegdT_LtE4k

    03 PSU12-sritrang features (ตอนที่ 3 คุณสมบัติของแต่ละเมนู)
    PSU12-sritrang-t03
    https://youtu.be/Dw_wAyMa3vA

    04 PSU12-sritrang control (ตอนที่ 4 การควบคุมเครื่องวินโดวส์ send, restart, shutdown, wakeonlan)
    PSU12-sritrang-t04
    https://youtu.be/o801BZ9ye0Y

    05 PSU12-sritrang prnews (ตอนที่ 5 ประชาสัมพันธ์ข่าวด้วยภาพ เมื่อ boot from network)
    PSU12-sritrang-t05
    https://youtu.be/FA2X182oKXo

    06 PSU12-sritrang windows master (ตอนที่ 6 เตรียมวินโดวส์ต้นฉบับที่ติดตั้ง cygwin)
    PSU12-sritrang-t06
    https://youtu.be/9XkLQQ-niz4

    07 PSU12-sritrang windows computer name (ตอนที่ 7 เปลี่ยนชื่อเครื่อง)
    PSU12-sritrang-t07
    https://youtu.be/TuW8_Z2U7V4

    08 PSU12-sritrang windows pgina freeradius (ตอนที่ 8 ตั้ง login ใช้ RADIUS server)
    PSU12-sritrang-t08
    https://youtu.be/58Pw-dbxljw

    09 PSU12-sritrang windows partitions (ตอนที่ 9 เตรียมฮาร์ดดิสก์ของวินโดวส์ต้นฉบับ)
    PSU12-sritrang-t09
    https://youtu.be/jP4oSqRNvCo

    10 PSU12-sritrang linuxmint master (ตอนที่ 10 เตรียมลินุกซ์มินท์ต้นฉบับ)
    PSU12-sritrang-t10
    https://youtu.be/zpR0UQbTy_U

    11 PSU12-sritrang control linuxmint (ตอนที่ 11 การควบคุมเครื่องลินุกซ์มินท์)
    PSU12-sritrang-t11
    https://youtu.be/bVtfc4x-kKU

    12 PSU12-sritrang server backup (ตอนที่ 12 สำเนาไฟล์เก็บไว้)
    PSU12-sritrang-t12
    https://youtu.be/dA7-pWjy35I

    และมีเอกสารแนะนำอยู่ที่ http://opensource.psu.ac.th/PSU-Open-server