|
Windows Form App : ทำให้หน้าจอไม่ค้างในขณะทำงานด้วย BackgroundWorker (VB.Net,C#) |
Windows Form App : ทำให้หน้าจอไม่ค้างในขณะทำงานด้วย BackgroundWorker (VB.Net,C#) ในการใช้งาน Background Process เป็นเทคนิคขั้น Advanced ของการเขียนโปรแกรม เพราะปกติแล้วการเขียนโปรแกรมบน Windows Form Application ทั่ว ๆ ไป ในขณะที่โปรแกรมกำลังทำงานด้วย Process ที่ทำงานนาน ๆ หนัก ๆ เราจะสังเกตุว่าหน้าจอนั้นค้างหรือแฮ้งไปชั่วขณะ และจะต้องรอจนกว่าโปรแกรมทำงานเสร็จ หน้าจอถึงจะ Active ให้ใช้งานได้อีกครั้ง ไม่สามารถที่จะยกเลิก หรือ Cancel ตัว Process ได้ และในหลาย ๆ โปรเจคที่ผมมารับช่วงต่อ (เก็บบั๊ก 555+) โปรแกรมเมอร์เก่า ๆ ก็ไม่ได้นำ BackgroundWorker มาใช้งานหรือให้ความสำคัญเลย ผลลัพธ์ที่ได้คือ โปรแกรมทำงานนานมาก และ หน้าจอค้างไปเฉย ๆ ทางยูสเซอร์เองก็ไม่ค่อยชอบกับ Interface แบบนี้ซะเท่าไหร่ เพราะมันเป็นการบ่งบอกถึงความรู้ความสามารถประสบการณ์การเป็นมืออาชีพในการเขียนโปรแกรมของเราได้เลย ซึ่งปกติเมือ่ก่อนแล้วเราอาจจะต้องประกาศพวก Thread ขึ้นมาใช้งาน แต่ใน .Net รุ่นใหม่ ๆ มี Class ของ BackgroundWorker ให้เราเรียกใช้งานได้เลย แทบจะเรียกใช้ได้สะดวกมาก ๆ และผมก็ค่อนข้างที่จะชอบมันมากด้วยเช่นเดียวกัน
BackgroundWorker Syntax (C#)
BackgroundWorker bgWorker = new BackgroundWorker();
private void btnStart_Click(object sender, EventArgs e)
{
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
bgWorker.ProgressChanged += new ProgressChangedEventHandler(bgWorker_ProgressChanged);
bgWorker.RunWorkerAsync();
}
private void btnStop_Click(object sender, EventArgs e)
{
bgWorker.CancelAsync();
}
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Do Work
}
// This event handler updates the progress.
private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Update Progress Status to UI
}
// This event handler deals with the results of the background operation.
private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Finish
}
BackgroundWorker Syntax (VB.Net)
Private WithEvents bgWorker As New BackgroundWorker
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
bgWorker.RunWorkerAsync()
End Sub
Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
bgWorker.CancelAsync()
End Sub
Private Sub bgWorker_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgWorker.DoWork
' Do Work
End Sub
Private Sub bgWorker_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bgWorker.ProgressChanged
' Update Progress Status to UI
End Sub
Private Sub bgWorker_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgWorker.RunWorkerCompleted
' Finish
End Sub
คำอธิบาย ในการใช้งาน BackgroundWorker จะมีการ Delegate ตัว Method ขึ้นมา 3 ตัวคือ
- DoWork เป็น Method ที่เริ่มทำงาน BackgroundWorker ในรูปแบบของ Background Process เราไม่สามารถส่งออก UI ออกทาง Method นี้ได้ จะต้องไปใช้ ProgressChanged
- ProgressChanged เป็น Method สำหรับส่งออกหรือแสดงค่า UI ออกทางหน้าจอ ซึ่งในขณะที่ทำงานที่ DoWork สามารถส่งออก Result เพื่อ Call ProgressChanged ได้ทุกระยะ
- RunWorkerCompleted เป็น method เมื่อ BackgroundWorker ทำงานเสร็จสิ้น
ปกติแล้วการทำงานในรูปแบบของ Process เราจะไม่ทราบว่าจะต้องใช้เวลาทำงานซะเท่าไหร่ ฉะนั้นในส่วนของ ProgressChanged เราอาจจะใช้เป็นรุปภาพ หมุ่น ๆ หรือ Loading แทน หรือจะใช้เป็นแบบ Dialog ProgressBar ก็ได้
Example : การใช้ BackgroundWorker ทำงานเป็น Background Process ป้องกันหน้าจอค้าง
ออกแบบหน้าจอดังรูป
Code (C#)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DemoProgressWorking
{
public partial class Form1 : Form
{
BackgroundWorker bgWorker;
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
// New BackgroundWorker
bgWorker = new BackgroundWorker();
bgWorker.WorkerReportsProgress = true;
bgWorker.WorkerSupportsCancellation = true;
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
bgWorker.ProgressChanged += new ProgressChangedEventHandler(bgWorker_ProgressChanged);
// Start the asynchronous operation.
bgWorker.RunWorkerAsync();
this.btnStart.Enabled = false;
}
private void btnStop_Click(object sender, EventArgs e)
{
if (bgWorker.WorkerSupportsCancellation == true)
{
// Cancel the asynchronous operation.
bgWorker.CancelAsync();
}
}
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
// This event handler updates the progress.
private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.lblResult.Text = (e.ProgressPercentage.ToString() + "%");
}
// This event handler deals with the results of the background operation.
private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
this.lblResult.Text = "Canceled!";
}
else if (e.Error != null)
{
this.lblResult.Text = "Error: " + e.Error.Message;
}
else
{
this.lblResult.Text = "Done!";
}
this.btnStart.Enabled = true;
MessageBox.Show("Working Finished.");
}
}
}
Code (VB.Net)
Imports System.ComponentModel
Public Class Form1
Private WithEvents bgWorker As BackgroundWorker
Public Sub New()
' This call is required by the designer.
InitializeComponent()
End Sub
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
' New BackgroundWorker
bgWorker = New BackgroundWorker
bgWorker.WorkerReportsProgress = True
bgWorker.WorkerSupportsCancellation = True
' Start the asynchronous operation.
bgWorker.RunWorkerAsync()
Me.btnStart.Enabled = False
End Sub
Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
If bgWorker.WorkerSupportsCancellation = True Then
' Cancel the asynchronous operation.
bgWorker.CancelAsync()
End If
End Sub
Private Sub bgWorker_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgWorker.DoWork
Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
Dim i As Integer
For i = 1 To 10
If (worker.CancellationPending = True) Then
e.Cancel = True
Exit For
Else
' Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500)
worker.ReportProgress(i * 10)
End If
Next
End Sub
Private Sub bgWorker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles bgWorker.ProgressChanged
Me.lblResult.Text = (e.ProgressPercentage.ToString() + "%")
End Sub
Private Sub bgWorker_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles bgWorker.RunWorkerCompleted
If e.Cancelled = True Then
Me.lblResult.Text = "Canceled!"
ElseIf e.Error IsNot Nothing Then
Me.lblResult.Text = "Error: " & e.Error.Message
Else
Me.lblResult.Text = "Done!"
End If
Me.btnStart.Enabled = False
MessageBox.Show("Working Finished.")
End Sub
End Class
Screenshot
ทดสอบการทำงาน
แสดงสถานะการทำงาน ซึ่งในส่วนนี้จะไม่ใช้เป็นเปอร์เซ็นต์ก็ได้ อาจจะแสดงรุปภาพ หรืออื่น ๆ เพื่อให้รู้ว่าโปรแกรมกำลังทำงาน
ในขณะโปรแกรมทำงาน หน้าจอจะไม่ค้าง สามารถคลิกหรือทำอย่างอื่นได้
Note!! ในตัวอย่างแรกจะเป็นการประกาส Class ของ BackgroundWorker ขึ้นมา แต่ปกติแล้วใน Windows Form Application มีเครื่องมือของ BackgroundWorker รองรับให้ใช้งานได้เลย
ลาก BackgroundWorker ขึ้นมาบน Form
เป็นส่วนของ Event ต่าง ๆ คือ .DoWork, .ProgressChanged และ .RunWorkerCompleted
Code (C#)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DemoProgressWorking
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void btnStart_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
this.btnStart.Enabled = false;
}
}
private void btnStop_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
// Cancel the asynchronous operation.
backgroundWorker1.CancelAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
// This event handler updates the progress.
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.lblResult.Text = (e.ProgressPercentage.ToString() + "%");
}
// This event handler deals with the results of the background operation.
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
this.lblResult.Text = "Canceled!";
}
else if (e.Error != null)
{
this.lblResult.Text = "Error: " + e.Error.Message;
}
else
{
this.lblResult.Text = "Done!";
}
this.btnStart.Enabled = true;
MessageBox.Show("Working Finished.");
}
}
}
BackgroundWorker Syntax (VB.Net)
Imports System.ComponentModel
Public Class Form1
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
BackgroundWorker1.WorkerReportsProgress = True
BackgroundWorker1.WorkerSupportsCancellation = True
End Sub
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
If BackgroundWorker1.IsBusy <> True Then
' Start the asynchronous operation.
BackgroundWorker1.RunWorkerAsync()
Me.btnStart.Enabled = False
End If
End Sub
Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
If BackgroundWorker1.WorkerSupportsCancellation = True Then
' Cancel the asynchronous operation.
BackgroundWorker1.CancelAsync()
End If
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
Dim i As Integer
For i = 1 To 10
If (worker.CancellationPending = True) Then
e.Cancel = True
Exit For
Else
' Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500)
worker.ReportProgress(i * 10)
End If
Next
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
Me.lblResult.Text = (e.ProgressPercentage.ToString() + "%")
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Cancelled = True Then
Me.lblResult.Text = "Canceled!"
ElseIf e.Error IsNot Nothing Then
Me.lblResult.Text = "Error: " & e.Error.Message
Else
Me.lblResult.Text = "Done!"
End If
Me.btnStart.Enabled = True
MessageBox.Show("Working Finished.")
End Sub
End Class
ซึ่งทั้ง 2 วิธีได้ผลลัพธ์ที่เหมือนกัน ขึ้นอยู่ว่าจะชอบวิธีไหนมากกว่า
.
|
|
|
|
|
|
|
|
By : |
TC Admin
|
|
Article : |
บทความเป็นการเขียนโดยสมาชิก หากมีปัญหาเรื่องลิขสิทธิ์ กรุณาแจ้งให้ทาง webmaster ทราบด้วยครับ |
|
Score Rating : |
|
|
Create Date : |
2015-10-08 |
|
Download : |
No files |
|
Sponsored Links |
|
|
|
|
|
|