Category: Developer

งานพัฒนาระบบ, เขียนโปรแกรม

  • การทำ Partial Rendering สำหรับ User Controls

    สำหรับท่านใดที่ยังใช้งาน ASP.NET Web From ในการพัฒนาเว็บไซต์อยู่ คงคุ้นเคยกับการใช้งาน User Controls เป็นอย่างดีเนื่องจากเป็นการสร้าง UI เพื่อใช้งานซ้ำในหลายๆ Page ซึ่งเป็นที่นิยม สำหรับบทความนี้จะแนะนำวิธีการ แยกเรนเดอร์ User Controls ที่มีปัญหาโหลดช้าอันเนื่องมาจากสาเหตุใดก็ตาม และเป็นข้อมูลเพิ่มเติมที่ผู้ใช้ไม่จำเป็นต้องเห็นเป็นอย่างแรก โดยมีขั้นตอนดังนี้

    1.เพิ่ม HTML Container element เช่น Div, Panel ในหน้าจอ ที่ต้องการใช้งาน เช่น

    2.เพิ่ม Ajax Controls toolkit : Dynamic Populate ใช้เพื่อ Render HTML หลังจากที่ Page Load เสร็จเรียบร้อย

    • TargetControlsID คือ ID ของ HTML Container element ที่เราต้องการแสดงผล HTML ของ User Controls ที่เราสร้างมาจาก Web Service
    • ServicePath คือ Path ของ Web Service ที่เรียกใช้งาน
    • ServiceMethod คือ Web Method ที่ใช้ Render User Controls
    • UpdatingCssClass คือ CSS Class ที่ต้องการให้แสดงระหว่างรอ Load HTML

    3.Java Script เรียกใช้งาน  Ajax Controls toolkit : Dynamic Populate และเพิ่มเติมฟังก์ชันที่ต้องการขณะแสดงผล User Controls

    4.สร้าง Web Method สำหรับสร้าง HTML ของ User Controls

    • รูปแบบของ Web Service Method ซึ่งจะต้องมี Return Type เป็น string และรับ Parameter ชื่อ contextKey ซึ่งมี Type เป็น string เช่นกัน
    • เรียก Method ชื่อ RenderUserControl โดยระบุ Path ของ User Control ที่ต้องการ และ List ของ Property ทั้งหมดของ User Control

    5.Method ที่ใช้ในการสร้างเนื้อหา HTML จาก User Controls

    เพียงเท่านี้ เราก็สามารถเรียกใช้งาน User Control นี้ในหน้าจอต่างๆ ได้โดยไม่ต้องกังวลเรื่องเพิ่มเวลาโหลดให้กับหน้าจอแสดงผลนั้นๆแล้วครับ อย่างไรก็ดีบทความนี้ผมได้เขียนไว้นานมากแล้ว แต่ยังไม่ได้นำมาเผยแพร่ ในปัจจุบันอาจมีวิธีการอื่นๆ และ ASP.NET ที่เป็น Web Form อาจจะได้รับความนิยมน้อยลงไปแล้ว แต่สำหรับท่านที่ต้องดูแล และปรับปรุงระบบเก่าๆ ไม่สามารถเขียนขึ้นมาใหม่ทั้งหมดได้ ก็ยังสามารถนำเทคนิคนี้ไปปรับใช้กับระบบของตนเองได้ครับ

  • ทำให้แอปพลิเคชันอ่านหรือสร้าง Barcode ได้ด้วย ZXing (“zebra crossing”)

    เนื่องด้วยได้รับโจทย์ให้พัฒนาแอปพลิเคชัน ที่สามารถแสกนบาร์โค้ดได้เมื่อได้ค้นหาดูก็พบชื่อของ Library ที่แรกเริ่มเขียนด้วยภาษา Java และถูก Port ให้รองรับภาษาอื่นๆอีกมากมาย เป็นที่นิยม และเป็น Open Source นั้นคือ ZXing โดยในบทความนี้จะแสดงตัวอย่างวิธีการนำ ZXing.Net.Mobile มาใช้งานร่วมกับ Xamarin.iOS

    ขั้นตอนการนำมาใช้งาน

    ตัวอย่างในบทความใช้ Visual Studio 2019 16.8.0 ติดตั้ง Work Load Xamarin.iOS

    1.สร้างโปรเจคใหม่โดยเลือก Template ชื่อ iOS App (Xamarin) และกำหนดค่าดังรูป

    2. โดยโครงสร้างไฟล์ของโปรเจคมีดังรูป

    3. เปิดไฟล์ Main.storybord สร้าง View และเพิ่มปุ่ม btnScanBarcode (สำหรับ Xamarin.iOS บน Windows จะไม่สามารถแก้ไขไฟล์ .storybord ได้แล้วในเวอร์ชันนี้ ต้องทำบน macOS เท่านั้น)

    4.ติดตั้ง ZXing.Net.Mobile ผ่าน Nuget Package โดยคลิกขวาที่ชื่อโปรเจค เลือก Manage Nuget Packages ค้นหาคำว่า ZXing เลือก Install

    5.สร้าง Controller สำหรับ View ที่ได้สร้างไว้ก่อนหน้านี้ และเพิ่มโค้ดดังนี้

    using System;
    using UIKit;
    using ZXing.Mobile;
    
    namespace ZXingScanBarcode
    {
        public partial class ViewController : UIViewController
        {
            public ViewController(IntPtr handle) : base(handle)
            {
            }
    
            public override void ViewDidLoad()
            {
                scanner = new MobileBarcodeScanner(this.View);
                btnScanBarcode.TouchUpInside += async (sender, e) =>
                {
                    scanner.UseCustomOverlay = false;
                    scanner.TopText = "Hold camera up to barcode to scan";
                    scanner.BottomText = "Barcode will automatically scan";
    
                    var result = await scanner.Scan(false);
    
                    HandleScanResult(result);
                };
    
            }
    
            void HandleScanResult(ZXing.Result result)
            {
                this.InvokeOnMainThread(() =>
                {
                    if (result != null && !string.IsNullOrEmpty(result.Text))
                    {
                        //แสดงค่าที่อ่านได้ใน UILabel
                        lblBarcode.Text = result.Text;
    
                        //เชื่อมต่อ API เพื่อใช้บาร์โค้ดที่อ่านได้ทำอะไรบางอย่าง ตรงนี้             
                    }
                    else
                    {
                        UIAlertController alert = UIAlertController.Create("Scanning Canceled!", string.Empty, UIAlertControllerStyle.Alert);
                        alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
                        PresentViewController(alert, true, null);
                    }
                });
            }
        }
    }
    

    6. จากนั้นให้เปิดไฟล์ info.plist เพื่อเพิ่มข้อมูลคำอธิบายการขอสิทธิการใช้กล้อง และส่วนอื่นๆที่ ZXing ต้องการดังรูป (ในส่วนคำอธิบายสามารถปรับเปลี่ยนให้ดีกว่านี้ได้)

    7.เพียงเท่านี้ก็สามารถกด Run เพื่อทดสอบกับอุปกรณ์ที่เชื่อมต่อได้แล้ว (ไม่สามารถทดสอบบน Simulator ได้เนื่องจากต้องใช้กล้อง)

    สำหรับบทความนี้ค่อนข้างจำเพาะเจาะจงกับเครื่องมือที่ใช้พัฒนาแอปพลิเคชัน ที่จะต้องเป็น Xamarin.iOS บน Visual Studio เท่านั้น แต่ด้วยชื่อของ ZXing ท่านที่ใช้เครื่องมืออื่นๆสามารถนำไปค้นหาเวอร์ชัน และวิธีการใช้งานสำหรับเครื่องมือนั้นๆเพิ่มเติมได้ อย่างน้อยก็เป็นการแนะนำให้นักพัฒนาที่ได้อ่านบทความนี้ ได้รู้จัก Library ในงานด้านนี้เพิ่มอีก 1 ตัวครับ

  • แก้ปัญหาอัปโหลด Android App ไม่ผ่านเพราะเปลี่ยนคนอัปโหลด

    เคยไหมที่ฝากทีมอื่นที่เขามี account google play console อยู่แล้ว เพื่อฝากอัพเดทแอปที่เราเพิ่ม feature ใหม่ๆของแอปที่เราพัฒนา ตอนนั้นก็ได้ลองผิดลองถูกกันไปเรื่อยๆ เพราะว่าตอนที่เรา build app มันจะสร้าง signing key ในการอัปโหลดที่ผูกติดกับ user ดังนั้นเมื่อเปลี่ยน user ในการอัปโหลดก็ต้องอัปโหลด signing key ใหม่

    วันนี้จะมา KM การเปลี่ยน signing key เผื่อใครเคยเจอปัญหาเดียวกัน

    หน้าจอแสดงการอัปโหลด Android app ไม่ผ่าน เพราะ signing key ไม่ตรงกับ user เก่า

    โดยเข้าที่เมนู App signing เพื่อดูรายละเอียดเพิ่มเติม

    หน้าจอแสดงรายละเอียด signing key ที่สามารถอัปโหลดจะเห็นได้ว่า SHA ผูกติดกับ user เก่า ดังนั้นเพื่อแก้ปัญหานี้ เราต้อง Upload certificate ใหม่

    โดยที่เราต้องไปที่ project ของเราเพื่อดึงค่า key store ใหม่ โดยใช้คำสั่ง expo fetch android:keystore (คำสั่งขึ้นอยู่กับ project ว่าใช้ Tool อะไร ถ้าใช้ Expo ใช้คำสั่งนี้) ก็จะเห็นค่า Key password ที่เราตั้งไว้ (ขั้นตอนนี้จะได้ไฟล์ .jks)

    การสร้าง signing key ใหม่ โดยใช้คำสั่ง expo fetch android:upload-cer (ขั้นตอนนี้เราจะได้ไฟล์ .pem)

    จากนั้นเราเราก็ส่งข้อมูลไฟล์ .pem โดยคลิก https://support.google.com/googleplay/android-developer/contact/key อัปโหลดไฟล์ .pem ใหม่ จากนั้นก็รอ mail แจ้งกลับจาก Google play console เมื่อ approved เรียบร้อยแล้ว เราก็จะอัปโหลดแอปได้ตามปกติ

    ที่มา : https://support.google.com/googleplay/android-developer/answer/9842756

  • แสดงข้อมูล Memory CPU Disk ด้วย C# EP.3

    แล้วก็มาถึง EP สุดท้ายของซีรีส์นี้ นั่นก็คือการดึงข้อมูลการใช้งานพื้นที่บน Disk

    ก่อนจะไปหาพื้นที่ disk เราต้องไปหา drive กันก่อนว่ามี drive อะไรบ้าง จากนั้นจึงไปหาข้อมูล disk ของ drive นั้นๆ โดยเราจะใช้ class DriveInfo สำหรับดึงข้อมูล drive ต่างๆ ออกมา ดังโค้ดตัวอย่าง

    โดยเราสามารถดึงข้อมูล drive ต่างๆ ได้ผ่านเมทธอด GetDrives() และเข้าถึงชื่อ drive ได้ผ่าน property Name

    เมื่อมาถึงขั้นตอนนี้ เราก็สามารถเข้าถึงข้อมูลพื้นที่ disk และการใช้งานของแต่ละ drive ได้ไม่ยากแล้ว ผ่าน property ต่างๆ ของ object DriveInfo เราไปดูตัวอย่างโค้ดกันเลย

    จากตัวอย่าง เราต้องตรวจสอบเพิ่มเติมว่า Drive ที่เราต้องการอยู่ในสถานะพร้อมใช้งานอยู่หรือไม่ผ่าน IsReady ก่อนที่จะเรียกใช้งานเมทธอดอื่น

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

    using System;
    using System.IO;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                long B2GB = 1024 * 1024 * 1024;
                DriveInfo[] drives = DriveInfo.GetDrives();
                foreach (DriveInfo drive in drives)
                {
                    if (drive.IsReady)
                    {
                        
                        Console.WriteLine("Drive : " + drive.Name);
                        Console.WriteLine("Total Size : " + (drive.TotalSize / B2GB ).ToString("0.00") + " GB" );
                        Console.WriteLine("Available Free Space : " + (drive.AvailableFreeSpace / B2GB).ToString("0.00") + " GB");
                    }
                }
            }
        }
    }
    

    ผลลัพธ์จากการรันโค้ดข้างต้น

    นอกจากนี้ DriveInfo ยังมีอีกหลาย property ที่เราสามารถเรียกใช้งานได้ ดังตัวอย่าง

    DriveInfo Properties
    AvailableFreeSpace Indicates the amount of available free space on a drive, in bytes.
    DriveFormat Gets the name of the file system, such as NTFS or FAT32.
    DriveType Gets the drive type, such as CD-ROM, removable, network, or fixed.
    IsReady Gets a value that indicates whether a drive is ready.
    Name Gets the name of a drive, such as C:.
    RootDirectory Gets the root directory of a drive.
    TotalFreeSpace Gets the total amount of free space available on a drive, in bytes.
    TotalSize Gets the total size of storage space on a drive, in bytes.
    VolumeLabel Gets or sets the volume label of a drive.

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

    สวัสดีครับ


    อ้างอิง

  • แสดงข้อมูล Memory CPU Disk ด้วย C# EP.2

    สำหรับ EP นี้เราก็มาถึงวิธีการดึงข้อมูลการใช้งาน CPU กัน เพื่อไม่ให้เป็นการเสียเวลา เรามาเริ่มกันเลย

    สำหรับการดึงข้อมูลนั้น เราก็สามารถใช้งาน object PerformanceCounter ได้เหมือนเดิม โดยจะต้องระบุ parameter ที่จำเป็นดังนี้

    PerformanceCounter cpu = new PerformanceCounter("Processor", "% Processor Time", "_Total");

    และเมื่อทดลองเรียกใช้งาน จะปรากฏผลดังภาพ

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

    จากตัวอย่าง หลังเรียกใช้งานครั้งแรก จะหน่วงเวลาไว้ 1 วินาที จึงเรียกใช้งานอีกครั้ง

    ซึ่งเทคนิคนี้ เอกสารของทาง Microsoft ก็ได้ระบุเอาไว้ ดังนี้

    If the calculated value of a counter depends on two counter reads, the first read operation returns 0.0. Resetting the performance counter properties to specify a different counter is equivalent to creating a new performance counter, and the first read operation using the new properties returns 0.0. The recommended delay time between calls to the NextValue method is one second, to allow the counter to perform the next incremental read.

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

    โดยผลลัพธ์จากโค้ดด้านบน ก็จะแสดงการทำงานของ CPU ทุก 1 วินาทีเป็นจำนวน 10 ครั้ง

    จะเห็นว่าการดึงข้อมูลการใช้งาน CPU ไม่ได้ยุ่งยาก แค่มีทริคนิดเดียวตรงที่จะต้องมีการเรียก NextValue() 2 ครั้ง และต้องมีการหน่วงเวลาก่อนการเรียกครั้งที่ 2 ก็จะได้ผลลัพธ์ที่ถูกต้อง

    แล้วพบกันใน EP หน้า สวัสดีครับ


    อ้างอิง

  • แสดงเครื่องหมายถูกใน Crystal Report

    นักพัฒนาหลายๆ ท่านที่ออกรายงานด้วย Crystal Report อาจจะมีความต้องการแสดงสัญลักษณ์เครื่องหมายต่างๆ บนตัวรายงาน แต่ไม่มีเครื่องมือที่ออกแบบมาเพื่อการนี้โดยตรง แต่เราสามารถทำได้ด้วยวิธีการดังต่อไปนี้

    1. สร้าง Formula Field และกำหนดชื่อให้เรียบร้อย

    2. ป้อนคำสั่ง Chr(254) จากนั้น Save

    3. เพิ่ม formula field ที่เพิ่งสร้างลงไปในรายงาน และเปลี่ยนฟอนต์ให้เป็น “Windings”

    4. เมื่อทดสอบดูรายงาน ก็จะแสดงเป็นเครื่องหมายถูกภายในกล่องสี่เหลี่ยมดังภาพ

    5. นอกจากนี้เราสามารถกำหนดให้แสดงผลเป็นรูปแบบอื่นๆ ได้ด้วยการแก้ไขโค้ดเป็นอย่างอื่น เช่น

    6. เมื่อเราทราบโค้ดของสัญลักษณ์ที่เราต้องการแล้ว เราก็สามารถควบคุมการแสดงผลด้วยการเพิ่มเงื่อนไขใน Formula Field ดังตัวอย่าง

    If {Table.Gender} = "M" Then
        Chr(254)    //แสดงเครื่องหมายถูกในกล่องสี่เหลี่ยม
    Else
        Chr(168)    //แสดงกล่องเปล่า
    End If

    อ้างอิง

    https://stackoverflow.com/questions/279907/checkbox-in-a-crystal-report

  • แสดงข้อมูล Memory CPU Disk ด้วย C# EP.1

    ในช่วงที่ผ่านมาผู้เขียนได้รับมอบหมายให้พัฒนาเครื่องมือสำหรับมอนิเตอร์การใช้งานทรัพยากรต่างๆ บน Server ที่ให้บริการลูกค้า ทั้งในส่วน Memory CPU และ Disk โดยโจทย์คือพัฒนา Service ขึ้นมาตัวนึงด้วยเครื่องมือที่เราใช้งานกันอยู่แล้วคือ Visual Studio.NET ด้วยภาษ C# สำหรับอ่านทรัพยากรต่างๆ บน Server แล้วจึงเขียนค่าเหล่านั้นลงไฟล์ จากนั้นจะมีเครื่องมืออีกตัวเข้ามาอ่านไฟล์ดังกล่าวแล้วนำไปแสดงผลเป็นกราฟในรูปแบบที่ต้องการต่อไป

    เริ่มต้นเรามาดูวิธีการดึงข้อมูลหน่วยความจำ Available (คงเหลือ) กันก่อน ซึ่งโชคดีที่ .NET มี object ตัวนึงที่ชื่อ PerformanceCounter ที่จะคอยเก็บข้อมูลต่างๆ ของ Server และเราสามารถดึงค่าต่างๆ มาใช้งานได้โดยการระบุ parameter ที่เราต้องการ อย่างเช่นในกรณีของหน่วยความจำ จะต้องระบุ parameter 2 ตัว คือ “Memory”, “Available MBytes” ดังโค้ดตัวอย่าง

    PerformanceCounter availMemory = new PerformanceCounter("Memory", "Available MBytes", null);

    โดยเราจะดึงข้อมูลออกมาผ่านเมทธอด NextValue() อย่างเช่น

    availMemory.NextValue();

    เมื่อทดลองรันโค้ดดังกล่าว โดยผู้เขียนได้ทดลองสร้างโปรเจ็คแบบ Console Application ได้ผลลัพธ์ดังต่อไปนี้

    โดยข้อมูลที่ได้อยู่ในรูปแบบ Megabytes ดังนั้นถ้าต้องการให้อยู่ในรูปแบบ Gigabytes จะต้องนำไปหารด้วย 1,024 เสียก่อน (ในส่วนนี้ผู้เขียนไม่แน่ใจว่า ในทางเทคนิคควรจะหารด้วย 1,024 หรือ 1,000)

    แต่ด้วยข้อจำกัด เราไม่สามารถหาหน่วยความจำทั้งหมดจาก PerformanceCounter โดยจะต้องดึงข้อมูลผ่านวิธีการอื่น นั่นคือการเรียกผ่าน Windows API Function และต้องประกาศ Structure เพิ่มเติมเพื่อให้รองรับข้อมูลที่ Windows API ส่งกลับมา ดังนี้

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private class MEMORYSTATUSEX
    {
    	public uint dwLength;
    	public uint dwMemoryLoad;
    	public ulong ullTotalPhys;
    	public ulong ullAvailPhys;
    	public ulong ullTotalPageFile;
    	public ulong ullAvailPageFile;
    	public ulong ullTotalVirtual;
    	public ulong ullAvailVirtual;
    	public ulong ullAvailExtendedVirtual;
    	
    	public MEMORYSTATUSEX()
    	{
    		this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
    	}
    }
    
    [return: MarshalAs(UnmanagedType.Bool)]
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);

    และตัวอย่างวิธีการเรียกใช้งานฟังก์ชัน

    ulong totalMemory;
    MEMORYSTATUSEX memStatus = new MEMORYSTATUSEX();
    if( GlobalMemoryStatusEx(memStatus))
    { 
       totalMemory = memStatus.ullTotalPhys;
    }

    เมื่อนำโค้ดไปทดสอบ จะได้ผลลัพธ์ดังภาพ

    โดยข้อมูลที่ได้จากฟังก์ชันนี้จะเป็นหน่วย byte ถ้าเราต้องการแปลงให้เป็น gigabyte ก็จะต้องหารด้วย (1024 * 1024 * 1024)

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

    ตัวอย่างโค้ดทั้งหมด

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            private class MEMORYSTATUSEX
            {
                public uint dwLength;
                public uint dwMemoryLoad;
                public ulong ullTotalPhys;
                public ulong ullAvailPhys;
                public ulong ullTotalPageFile;
                public ulong ullAvailPageFile;
                public ulong ullTotalVirtual;
                public ulong ullAvailVirtual;
                public ulong ullAvailExtendedVirtual;
                public MEMORYSTATUSEX()
                {
                    this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
                }
            }
    
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
    
            static void Main(string[] args)
            {
                float totalMemory = 0;
                MEMORYSTATUSEX memStatus = new MEMORYSTATUSEX();
                if (GlobalMemoryStatusEx(memStatus))
                {
                    totalMemory = memStatus.ullTotalPhys;
                    totalMemory = totalMemory / (1024 * 1024 * 1024);
                }
    
                PerformanceCounter pAvailMemory = new PerformanceCounter("Memory", "Available MBytes", null);
                
                Console.WriteLine("Total : " + totalMemory.ToString("0.00"));
                Console.WriteLine("Available : " + (pAvailMemory.NextValue() / 1024).ToString("0.00"));
                Console.WriteLine("Usage : " + (totalMemory - (pAvailMemory.NextValue() / 1024)).ToString("0.00"));
            }
        }
    }

    สำหรับวิธีการดึงหน่วยความจำของเครื่องก็คงจบลงเพียงเท่านี้ ครั้งหน้าเราจะมาดูวิธีการดึงข้อมูลการใช้งาน CPU กัน

    สวัสดีครับ


    อ้างอิง

  • ทำ functional design อย่างง่ายด้วยโปรแกรม Sandcastle Help File Builder

    เมื่อพัฒนาโปรแกรมเสร็จแล้ว ก็ถึงเวลาทำเอกสารการเขียนอธิบายโค้ดต่อ บางครั้งมันยุ่งยากเสียเวลา วันนี้มีวิธีที่สะดวกและรวดเร็วเพียงแค่เขียนอธิบายใน Class ที่เราต้องการอธิบาย เช่น Constructors, Properties, methods

    ตัวอย่างการเขียนอธิบายโค้ด

    โดยทั่วไปแล้วการเขียน Logic ต่างๆ เพื่อนำไปใช้งานต่อหรืออ้างอิงโค้ดที่เราเขียนมักจะ build code เป็นไฟล์ .dll เพื่อให้ระบบอื่นมาเชื่อมต่อและเรียกใช้งานได้ โดยขั้นตอนแรกเราใช้โปรแกรม Sandcastle Help File Builder สามารถอ่านรายละเอียดเพิ่มเติมตามลิ้งก์ https://github.com/EWSoftware/SHFB/releases และ download และติดตั้งตามลิ้งก์

    SHFBInstaller_v2019.11.17.0.zip 45.1 MB

    เมื่อติดตั้งเสร็จเรียบร้อย หน้าตาก็จะประมาณนี้

    โปรแกรม Sandcastle Help File Builder

    ก่อนอื่นเราต้องไปตั้งค่าการ build code ใน Visual Studio ในส่วนของ XML ตามไฮไลต์สีเหลือง

    การตั้งค่า XML ใน Visual Studio

    จากนั้นก็กด Build ใน Visual Studio

    แสดงการ Build ใน Visual Studio

    เมื่อ build เสร็จ เราจะได้ไฟล์ .dll และ .xml

    ไฟล์ .dll และ .xml

    เมื่อได้ไฟล์ .dll และ .xml เรียบร้อยแล้ว ก็เพิ่มในโปรแกรม Sandcastle Help File Builder โดยไปที่เมนู File > Project Explorer > Documentation Sources > Add Documentation Source

    เมนูการเพิ่ม Add Documentation Source

    เมื่อเลือกไฟล์ .dll และ .xml เรียบร้อยแล้ว ผลลัพธ์ที่ได้แสดงตามภาพ

    แสดงผลลัพธ์เมื่อ Add Documentation Source เสร็จ

    จากนั้นตั้งค่าเมนู Help File ตามตัวอย่างข้างล่าง

    ตั้งค่าเมนู Help File

    จากนั้นตั้งค่าเมนู Visibility ตามตัวอย่างข้างล่าง

    ตั้งค่าเมนู Visibility

    เมื่อตั้งค่าโปรแกรมเสร็จเรียบร้อยแล้ว ไปที่เมนู Documentation > Build Project

    เมนู Documentation > Build Project

    รอโปรแกรมประมวลผลสักครู่ เราก็จะได้ไฟล์ .chm ออกมา

    ไฟล์ .chm

    เมื่อเปิดไฟล์ .chm เราก็จะได้ผลลัพธ์ Help File ตามรูปแบบที่แสดงตามภาพด้านล่าง

    ผลลัพธ์ Help File 1
    ผลลัพธ์ Help File 2
    ผลลัพธ์ Help File 3
    ผลลัพธ์ Help File 4
  • ตรวจสอบการสะกดคำด้วย NHunspell (.Net Framework Library)

    สำหรับแอปพลิเคชันที่มีส่วนค้นหาแล้วนั้น หนีไม่พ้นคำถามจากผู้ใช้ว่า ถ้าสะกดคำผิดจะค้นเจอมั้ย (ก็ไม่เจอซิครับ) พร้อมยกตัวอย่างความสามารถในการแก้คำผิดของ Google, Bing ให้ฟัง สำหรับนักพัฒนาตัวคนเดียว หรือทีมงานเล็กๆ ที่ไม่สามารถใช้แนวทาง API แบบต้องมีค่าใช้จ่าย หรือ Machine Learning ที่ต้องใช้ความรู้เฉพาะด้าน ผมก็มี Library ขนาดเล็กที่อาศัยวิธีการทางสถิติ และไฟล์คลังคำศัพท์ (Dictionary) มาใช้งานไปก่อนครับ โดยได้ทำการทดสอบประสิทธิภาพเปรียบเทียบกับ PyThaiNLP, WeCantSpell.Hunspell มาแล้วทั้งในด้านความเร็ว และความถูกต้อง พบว่าดีที่สุด นั้นคือ NHunspell

    ขั้นตอนการนำมาใช้งาน

    ในตัวอย่าง เป็นการนำมาใช้งานร่วมกับ Console Application

    1.เปิด Nuget Manager ด้วยการ คลิกขวาที่ชื่อโปรเจค เลือก Manage Nuget Packages

    2.ค้นหา NHunspell เลือก Install

    3.สร้างโฟลเดอร์สำหรับเก็บไฟล์ Dictionary โดยสามารถดาวส์โหลดได้จาก https://github.com/LibreOffice/dictionaries นำไปวางไว้ที่ [ProjectPath]/bin/Debug

    4.สร้างโฟลเดอร์สำหรับเก็บไฟล์คำตัวอย่าง sentense_list.txt โดยมีบรรทัดละ 1 คำ เพื่อทำการโหลดข้อมูลเข้ามาให้ Library ประมวลผล และเก็บไฟล์ผลลัพธ์ไว้ที่ suggest_result.txt นำไปวางไว้ที่ [ProjectPath]/bin/Debug

    5. จากนั้นก็เขียนโค้ดในไฟล์ Program.cs ดังนี้

    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;
    using NHunspell;
    
    namespace SpellCheckTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    using (var sr = new StreamReader("example_data/sentense_list.txt"))
                    {
                        //อ่านรายการคำ
                        string searchterm = sr.ReadToEnd();
                        string[] searchtermArray = searchterm.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
    
                        Console.WriteLine("Processing...");
    
                        using (var sw = new StreamWriter("example_data/suggest_result.txt"))
                        {
                            foreach (string sentense in searchtermArray)
                            {
                                string result = string.Empty;
                                var startTime = System.DateTime.Now.Ticks;
    
                                //ส่งคำให้ NHunspell ประมวลผล
                                result = SuggestNHunSpell(sentense);
    
                                var endTime = System.DateTime.Now.Ticks - startTime;
                                TimeSpan elapsedSpan = new TimeSpan(endTime);
    
                                //เขียนผลการตรวจสอบ และเวลาที่ใช้ลงในไฟล์ผลลัพธ์
                                sw.WriteLine(result);
                                sw.WriteLine(string.Format("{0}", elapsedSpan.TotalSeconds));
                                sw.WriteLine();
                                sw.Flush();
                            }
                        }
    
                        Console.WriteLine("Process Complete.");
                        Console.ReadKey();
                    }
                }
                catch (IOException e)
                {
                    Console.WriteLine("The file could not be read:");
                    Console.WriteLine(e.Message);
                    Console.ReadKey();
                }
            }
    
            /// <summary>
            /// NHunSpell
            /// </summary>
            /// <param name="sentence"></param>
            /// <returns></returns>
            private static string SuggestNHunSpell(string sentence)
            {
                //ตรวจสอบว่าเป็นภาษาอังกฤษ หรือภาษาไทย
                bool IsEnglish = Regex.IsMatch(sentence.Replace(" ", string.Empty), "[a-zA-Z]");
    
                string dictPath = IsEnglish ? "dict/en_US.dic" : "dict/th_TH.dic";
                string affixPath = IsEnglish ? "dict/en_US.aff" : "dict/th_TH.aff";
                
                //โหลดไฟล์ Dict และ Affix 
                using (Hunspell hunspell = new Hunspell(affixPath, dictPath))
                {
                    //ตรวจสอบว่าสะกดถูกหรือไม่
                    if (!hunspell.Spell(sentence))
                    {
                        List<string> suggestions = hunspell.Suggest(sentence);
                        if (suggestions.Count > 0)
                        {
                            //คืนค่า รายการคำที่น่าจะเป็นคำสะกดที่ถูกต้อง
                            return sentence + " : " + string.Join(",", suggestions);
                        }
                    }
                }
    
                //หากตรวจสอบว่าสะกดถูกแล้ว บันทึกผลว่า Correct
                return sentence + ": Correct";
            }
        }
    }

    6.จากนั้นทำการ Run แบบ Debug จะปรากฎหน้าจอ Command Line แสดงข้อความ Processing… รอจนเห็นคำว่า Process Complete. แสดงว่าทำการประมวลผลเสร็จแล้ว

    7.ผลลัพธ์จะถูกบันทึกลงในไฟล์ suggest_list.txt ดังรูป

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