วันพฤหัสบดีที่ 18 พฤศจิกายน พ.ศ. 2553

เริ่มต้นการเขียนครั้งแรกด้วย BackgroundWorker

BackgroundWorker คืออะไร

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

BackgroundWorker เป็น Component Class นึงที่อยู่ใน System.ComponentModel
หากเปิดหน้า Design ใน VS.NET จะมี Control อยู่ในส่วน Components ของ Toolbox

BackgroundWorker นั้นเป็นคลาสที่ช่วยให้โปรแกรมเมอร์สามารถรันการดำเนินการ (Operation) บนเธรด (Thread) ใหม่ ซึ่งจะช่วยแก้ปัญหาที่กล่าวมาในตอนแรกได้

โดย BackgroundWorker จะมี Events สำคัญอยู่ 3 ตัวคือ
Dowork ทำหน้าที่รันการดำเนินการแบบ Background อีเว้นท์ถัดไปคือ ProgressChanged จะทำหน้าที่เมื่อมีการรายงานความคืบหน้าของการดำเนินการที่ทำงานอยู่ 
ส่วนอีเว้นท์สุดท้ายคือ RunWorkerCompleted จะทำงานเมื่อ การเดินเนินการที่ทำงานอยู่เสร็จสมบูรณ์

เพื่อให้เห็นภาพการทำงาน เรามาสร้างโปรแกรมง่ายๆ ขึ้น เพื่อจะได้เข้าใจการทำงานของมัน

1. สร้าง Window Application project ขึ้นมาก่อน



2. จากนั้นให้ลาก Control จาก Toolbox มาวางตามรูป ซึ่งประกอบด้วย label , Button และ Progressbar

3. คราวนี้หากเราต้องการนับตัวเลขหนึ่งถึง 20 เมื่อกดปุ่ม โดยให้แสดงตัวเลขที่ label และให้ Progressbar แสดงความคืบหน้า โดยจะนับแต่ละตัวห่างกัน 1 วินาที
ซึ่งครั้งแรกเราจะยังไม่ใช้งาน BackgroundWorker แล้วมาดูผลว่าเป็นยังไง

ตัวอย่างโค้ด
Imports System.Threading
Public Class Form1

    Private Sub btnDoWork_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDoWork.Click

        pgbWork.Value = 0
        pgbWork.Maximum = 100
        lblStatus.Text = String.Empty
        CountNumber()

    End Sub

    Private Sub CountNumber()

        Dim intCount As Integer = 1
        Dim intMaxNum As Integer = 20

        For intCount = 1 To intMaxNum

            Display(intCount.ToString)
            UpdateProgress((100 / intMaxNum) * intCount)
            Thread.Sleep(1000)

        Next

    End Sub

    Private Sub Display(ByVal strNum As String)

        lblStatus.Text = strNum

    End Sub

    Private Sub UpdateProgress(ByVal intPercent As Integer)

        pgbWork.Value = intPercent

    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        pgbWork.Value = 0
        pgbWork.Maximum = 100
    End Sub

4. จะเห็นว่าเมื่อเรารันโปรแกรม แล้วกดปุ่ม DoWork โปรแกรมเหมือนจะค้างไป ไม่สามารถทำอะไรได้ เช่นเวลา Minimize ลงมาที่ Task Bar จะไม่สามารถ Active มันขึ้นมาได้ จนกว่าโปรแกรมจะทำงานเสร็จ
หรือตัว Label ไม่อัพเดทตามที่เราเขียนโค้ดไว้



5. คราวนี้มาถึงตาพระเอกของเราบ้าง  เราจะเอา BackgroundWorker มาใช้งาน แล้วดูผลกันว่าแตกต่างกันอย่างไร
6. เริ่มด้วยให้ลาก Control Components ที่ชื่อ BackgroundWorker มาไว้ที่ฟอร์มของเรา จะสังเกตว่ามีไอคอน BackgroundWorker มาปรากฎในช่อง Component ด้านล่าง จากนั้นให้ตั้งชื่อ ในที่นี้ผมตั้งว่า
    wrkSample

7. จากนั้นให้กำหนด Properties ของ BackgroundWorker โดยกำหนด WorkerReportsProgress เป็น True เพื่อที่เราสามารถอัพเดทค่าของ label ได้

8. ต่อไปให้กำหนดในส่วน Events โดยกดที่รูปสายฟ้า แล้วให้ทำการดับเบิ้ลคลิกที่ช่องว่างๆ หลังชื่อ Event เราจะได้ Event มา 3 ตัวและมีการสร้างให้อันตโนมัติในส่วน Coding

    Private Sub wrkSample_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles wrkSample.DoWork

    End Sub

    Private Sub wrkSample_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles wrkSample.ProgressChanged

    End Sub

    Private Sub wrkSample_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles wrkSample.RunWorkerCompleted

    End Sub

9. มาเริ่มในส่วน Coding กัน เริ่มแรกคือ การเรียกใช้งาน BackgroundWorker เมื่อมีการกดปุ่ม DoWork

   If wrkSample.IsBusy <> True Then
            ' Start the asynchronous operation.
            wrkSample.RunWorkerAsync()
   End If

10. เมื่อเรียกใช้ Method ชื่อ RunWorkerAsync โปรแกรมจะเรียกใช้งานอีเว้นท์ชื่อ wrkSample_DoWork ทันที ซึ่งการทำงานหลักๆ เราจะเขียนไว้ที่นี้

  Private Sub wrkSample_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles wrkSample.DoWork

        Dim intCount As Integer = 1

        For intCount = 1 To intMaxNum

            wrkSample.ReportProgress(intCount)
            Thread.Sleep(1000)

        Next

    End Sub

11. จะเห็นว่ามีการเรียก Method ชื่อ ReportProgress โดยเมื่อเรียกใช้งาน โปรแกรมจะเรียกใช้งานอีเว้นท์ชื่อ wrkSample_ProgressChanged ทันที  ซึ่งใน Event นี้เองที่เราสามารถอัพเดท label และ progressbar ได้

    Private Sub wrkSample_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles wrkSample.ProgressChanged

        lblStatus.Text = e.ProgressPercentage.ToString()   '// ค่าที่ส่งมาทาง Parameter ของ Method ชื่อ ReportProgress
        pgbWork.Value = (100 / intMaxNum) * e.ProgressPercentage

    End Sub

12. สุดท้ายเมื่อโปรแกรมทำงานเสร็จสิ้นจะมีการเรียกใช้งานอีเว้นท์ที่ชื่อ wrkSample_RunWorkerCompleted โดยเรามาสามารถอัพเดทค่าของ Control ต่างๆ ได้เช่นกัน

    Private Sub wrkSample_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles wrkSample.RunWorkerCompleted
        lblStatus.Text = "Completed"
    End Sub

13. ทดลองรันโปรแกรม จะเห็นว่า Label นั้นเปลี่ยนไปตามที่เรากำหนดไว้ โดยไม่มีอาการค้างให้เห็นแต่อย่างใด






หวังว่าบทความนี้จะมีประโยชน์แก่ผู้อ่านนะครับ

อ้างอิง

1 ความคิดเห็น: