Hướng dẫn sử dụng BackgroundWorker để xây dựng chức năng Chạy nền trong C#

Đăng ký tài khoản kiếm tiền với tiếp thị liên kết tại ACCESSTRADE, MasOffer, Lazada Việt Nam

Để hỗ trợ lập trình viên phát triển các chức năng đa tiến trình, tiến trình chạy song song (chạy nhiều tác vụ cùng một lúc mà không phải đợi tiến trình trước hoàn tất) C# đã cung cấp cho bạn lớp Thread trong namspace System.Threading. Tuy nhiên, chắc chắn rằng việc sử dụng Thread đòi hỏi bạn phải có những kiến thức cũng như kiến thức nhất định để có thể xử lý. Đó là nói về Threading.

☛ Bạn có thể tải mã nguồn (source sample) bằng C# tại http://adf.ly/znuem

Trong bài viết này mình sẽ chia sẻ cùng bạn về BackgroundWorker một component trong System.ComponentModel. Đây là lớp được .Net tích hợp nhằm giúp lập trình viên xây dựng, quản lý các tiến trình chạy nền trong ứng dụng dễ dàng hơn và hiệu xuất tốt hơn, dễ dàng hơn so với việc sử dụng Thread.
Hiện tại BackgroundWorker (.Net phiên bản mình sử dụng là 4.0) thì lớp này được cung cấp các thuộc tính sau:

1. Các thuộc tính chủ yếu:
WorkerReportsProgress : mặc định là False. Thuộc tính này nếu là True thì event ProgressChanged sẽ được thực thi (trong này bạn xử lý để hiển thị tiến độ công việc như thanh xử lý tiến trình, % tiến trình).
WorkerSupportsCancellation : mặc định là False. Thuộc tính này nếu là True thì thao tác ngừng tiến trình có hiệu lực.
CancellationPending : biến bool tiếp nhận trạng thái dừng tiến trình. Nếu giá trị là True tức là tiến trình được yêu cầu dừng.
IsBusy: biến bool tiếp ghi nhận trạng thái hoạt động của BackgroundWorker, mặc định là False. Nếu kiểm tra (!IsBusy) thì tức là tiến trình đang bận xử lý.

2. Các sự kiện chính trong lớp BackgroundWorker:
DoWork: các thao tác xử lý công việc (lấy dữ liệu, tìm kiếm, update…) được diễn ra tại đây.
ProgressChanged: các xử lý hiển thị thông báo tiến độ của tiến trình đặt ở đây.
RunWorkerCompleted: các xử lý khi tiến trình hoàn tất hoặc bị ngừng bởi người dùng.

3. Để hiểu rõ hơn về cách sử dụng BackgroundWorker mình xin đưa ra 1 ví dụ cụ thể như sau:
Mình xây dựng 1 ứng dụng đơn giản chạy 1 vòng lặp for để hiển thị lên TextBox lần lượt chuỗi nội dung từ 0->n. Mã nguồn mình Upload tại link cuối bài viết. Nếu bạn quan tâm đến video hướng dẫn thì có thể xem thêm video sau:

(Video hướng dẫn sử dụng BackgroundWorker lập trình đa tiến trình trong C#)

Bạn vui lòng tham khảo các bước sau nhé !

a. Đầu tiên bạn tạo 1 dự án với các Controls như sau:

Hướng dẫn sử dụng BackgroundWorker trong xây dựng chức năng Chạy nền trong CSharp

b. Mã xử lý trong quá trình khởi tạo Form như sau:

public Form1()
        {
            InitializeComponent();
            backgroundWorker1=new BackgroundWorker();
            backgroundWorker1.WorkerReportsProgress=true;
            backgroundWorker1.WorkerSupportsCancellation = true;
            //Đăng ký các event cho backgroundWorker1;
            backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
            backgroundWorker1.RunWorkerCompleted +=
                new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
            backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
        }

c. Hàm xử lý tiến trình, trong hàm này các bạn đặt các thao tác xử lý của mình vào đây nhé, ở đây mình đặt thao tác xử lý vòng for cho phép hiển thị chuỗi tương ứng với chỉ số i:

private int demQuaTrinhXuLyDangChay = 0;
private void hamChuaCacThaoTacXuLyBangDoWorkBackground(DoWorkEventArgs e)
{
    for (Int64 i = Convert.ToInt64(txtChayTu.Text.Trim()); i < Convert.ToInt64(txtChayDen.Text.Trim()); i++)
    {
        //Đoạn này để chỉnh thời gian tạm ngừng giữa mỗi lần lặp của vòng for (lần xử lý);
        //Giá trị Sleep tính như sau 1000 = 1 giây;
        Thread.Sleep(Convert.ToInt16(txtThoiGianTamNgungGiuaCacLanXuLy.Text));
        //Kiểm tra trạng thái backgroundWork nếu bị ngừng thì dừng xử lý;
        if (backgroundWorker1.CancellationPending)
        {
            e.Cancel = true;
            return;
        }
        //Đoạn này để gọi event ReportProgress trong quá trình xử lý lần lặp i;
        //Ở đây mình đơn giản chỉ chạy dòng chữ ... cứ vậy cho đến khi xử lý hoàn tất thì hiển thị thông báo;
        demQuaTrinhXuLyDangChay++;
        backgroundWorker1.ReportProgress(demQuaTrinhXuLyDangChay);
        txtKetQuaXuLyTienTrinh.Text += i + ": [" + demQuaTrinhXuLyDangChay + "] lần xử lý "+i+" hoàn tất !rn";
        //Đoạn này để hiển thị tiến trình đang xử lý đến lần lặp i;
        txtKetQuaXuLyTienTrinh.SelectionStart = txtKetQuaXuLyTienTrinh.Text.Length;
        txtKetQuaXuLyTienTrinh.ScrollToCaret();
    }
}

d. Bạn viết mã xử lý cho các hàm sự kiện backgroundWorker1 như sau:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    //Gọi hàm xử lý tiến trình trong sự kiện DoWork;
    hamChuaCacThaoTacXuLyBangDoWorkBackground(e);
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    lblQuaTrinhXuLyTienTrinhHienTai.Text += ".";
    //Nếu label có hơn 3 dấu chấm thì gán lại giá trị rỗng cho thuộc tính Text;
    //Quá trình này sẽ được lặp lại cho đến khi tiến trình hoàn tất;
    //Bạn có thể sử dụng hình ảnh thể hiện dạng (loading...), đang xử lý để hiển thị cho người dùng biết;
    if (lblQuaTrinhXuLyTienTrinhHienTai.Text.Length >= 4)
    {
        lblQuaTrinhXuLyTienTrinhHienTai.Text = string.Empty;
    }
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
    {
        MessageBox.Show("Tiến trình xử lý được kết thúc bởi người dùng !", "Thông báo");
    }
    else
    {
        MessageBox.Show("Tiến trình xử lý hoàn tất !", "Thông báo");
        lblQuaTrinhXuLyTienTrinhHienTai.Text = string.Empty;
    }
}

e. Bạn viết mã xử lý sự kiện Click cho nút Chạy và Ngừng như sau:

private void btnChayTienTrinhXuLy_Click(object sender, EventArgs e)
{
    //Nếu backgroundWorker1 đang không trong quá trình xử lý thì chạy nó để bắt đầu xử lý;
    if(!backgroundWorker1.IsBusy)
    {
        backgroundWorker1.RunWorkerAsync();
    }
    //....
    //Bạn có thể viết mã hành xử thêm ở đây nếu tiến trình đang bận để tương tác;
}

private void btnNgungTienTrinhXuLy_Click(object sender, EventArgs e)
{
    //Ngừng tiến trình đang xử lý;
    backgroundWorker1.CancelAsync();
    txtKetQuaXuLyTienTrinh.Text = string.Empty;
    demQuaTrinhXuLyDangChay = 0;
}

Bây giờ bạn tiến hành Build dự án của mình để xem kết quả nhé !. Đối với việc xử lý các tiến trình khác các bạn làm tương tự, tùy vào mục đích yêu cầu mà xây dựng các tiến trình làm việc với nhau sao cho hợp lý.

☛ Bạn có thể tải mã nguồn (source sample) bằng C# tại http://adf.ly/znuem

Qua chia sẻ này mình mong sẽ giúp ích cho các bạn trong quá trình tiếp cận ngôn ngữ lập trình .Net (C#) để học tập cũng như phát triển ứng dụng của mình tốt hơn.
Cảm ơn sự quan tâm của bạn với chia sẻ về việc sử dụng BackgroundWorker trong việc lập trình đa tiến trình trong .NetFramwork.

Hướng dẫn sử dụng BackgroundWorker để xây dựng chức năng Chạy nền trong C# 4.50/5 (90.00%) 10 votes
Nếu bạn mong muốn tìm hiểu rõ hơn về chia sẻ này và những chia sẻ khác, bạn có thể kết nối với mình qua các thông tin sau:
Facebook (vui lòng add friend mình trước vì message ẩn mình ít check): https://www.facebook.com/PExpress
Blog: PolygonExpress.com
Group thảo luận - chia sẻ - bán ứng dụng - PolyXGO: MMO tools
Web dịch vụ: PolyXGO.com
Mã Giảm Giá mua sắm: Mã Giảm Giá Guru
Email liên hệ: polyxgo@gmail.com
Điện thoại: 0937.798.420 - 0868.929.024 (Kim Ngọc - giới tính Nam :))))))

Related

Sử dụng Stopwatch so sánh tốc độ xử lý trong .Net


Test ứng dụng có lẽ là khái niệm không còn xa lạ với dân lập trình viên, đặc biệt là các tester để xử lý lỗi, so sánh tốc độ xử lý... Việc viết Unit Test có thể không phải lập trình viên nào cũng có thể làm tốt và hiệu quả được, việc viết test sẽ đảm bảo chương trình của bạn tốt hơn, ít lỗi hơn, tốc độ xử lý cải thiện hơn khi sử dụng các thuật toán, loại dữ liệu, hàm chức năng phù hợp.Trong phạm vi bài viết mình không nói về Unit Test trong việc kiểm tra, so sánh tốc độ xử lý của chương trình, hàm chức năng nào đó ? Mà mình muốn nói đến Stopwatch. Đúng vậy, bằng cách viết 1 đoạn mã ngắn gọn như sau là mình đã có thể kiểm tra được tốc độ xử lý tương đối giữa các thao tác xử lý một đoạn mã lệnh nào đó.Ví dụ sau mình dùng Stopwatch để kiểm tra hiệu xuất khi sử dụng Generic collection và non-Generic collection trong việc lưu trữ dữ liệu vào mảng dạng danh sách.
Stopwatch wt = new Stopwatch();
string tmpStr=string.Empty;
List<string> ListGenerateCollection=new List<string>();
ArrayList ListNonGenerateCollection=new ArrayList();
wt.Start();
for (int i = 0; i < 10000; i++)
{
    ListGenerateCollection.Add(i.ToString());
}
wt.Stop();
tmpStr+="List<T>: "+wt.Elapsed.ToString()+"\r\n";

wt.Reset();
wt.Start();
for (int i = 0; i < 10000; i++)
{
    ListNonGenerateCollection.Add(i);
}
wt.Stop();
tmpStr+="ArrayList: "+wt.Elapsed.ToString()+"\r\n";
MessageBox.Show(tmpStr,"^^");
Kết quả hiển thị sau khi chạy ứng dụng cho thấy sử dụng Generic Collection (các tập hợp định kiểu strong-type, kiểu dữ liệu mạnh) trong .Net tốc độ xử lý nhanh hơn so với Non-Generic Collection (các tập hợp không định kiểu: object). Tuy nhiên, đây chỉ là ví dụ để so sánh tốc độ xử lý tương đối, còn việc sử dụng Generic collection hay non-Generic collection nó phụ thuộc vào yêu cầu của chương trình cũng như loại dữ liệu yêu cầu.Bạn có thể sử dụng đoạn mã trên để kiểm tra quá trình load dữ liệu, so sánh function (ví dụ tốc độ xử lý giữa SubString và Remove), hay loại xử lý mà trong đó KHÔNG phải phụ thuộc vào độ trễ của tiến trình.
In "C#"

Kiểm tra trạng thái Yahoo, Skype và sử dụng ảnh tuỳ ý theo trạng thái


Làm thể nào để kiểm trạng thái trực tuyến của tài khoản Yahoo, Skype ?. Mình xin chia sẻ cùng bạn lớp đáp ứng được yêu cầu của câu hỏi vừa rồi, tuỳ vào mục đích sử dụng, yêu cầu trên bản thiết kế bạn có thể phát triển lại theo ý mình (vì thường phần hỗ trợ trực tuyến trên website sẽ phải phù hợp với thiết kế tổng thể của website điều mà các icon mặc định của Yahoo, Skype không đáp ứng được).A. Giải pháp: 1. Request services (check Yahoo, Skype) của máy chủ Yahoo và Skype trả về trạng thái Online/ Offline với nick đầu vào.
StatusSupport(string yahooID)
2. Dựa trên trạng thái trả về tự động xuất mã HTML (template) hiển thị theo ý muốn.
WriteSupport(string yahooID, string pathImageOnline, string pathImageOffline, string alt)
B. Code demo: Đoạn mã mình chia sẻ chỉ mang tính tham khảo, các tham số trong các hàm đáp ứng nhu cầu mình sử dụng, bạn chỉ nên xem để tham khảo, sau đó bổ sung sửa đổi theo yêu cầu của mình.
Lưu ý khá quan trọng là: đối với nick Skype để kiểm tra được trạng thái Online/ Offline thì thuộc tính 'Show my status on the web' PHẢI ĐƯỢC CHECK nhé ! Để check thuộc tính này bạn mở chương trình Skype lên vào Tools -> Options -> Privacy Settings -> check chọn mục 'Allow my Online status to be show on the web'
Đầu tiên ta sẽ xây dựng lớp và các phương thức như sau:
public class Support
        {
            /// <summary>
            /// Hàm generate HTML hỗ trợ trực tuyến bằng yahoo;
            /// </summary>
            public class Yahoo
            {
                /// <summary>
                /// Trả về trạng thái của nick Yahoo;
                /// </summary>
                /// <param name="yahooID">Nick yahoo</param>
                /// <returns>Chuỗi trả về ONLINE hoặc OFFLINE</returns>
                private static string StatusSupport(string yahooID)
                {
                    string strStatus = "OFFLINE";
                    try
                    {
                        StringBuilder sb = new StringBuilder();
                        byte[] buf = new byte[8192];
                        string url = "http://opi.yahoo.com/online?u=" + yahooID + "&m=t";
                        HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
                        HttpWebResponse response = (HttpWebResponse) request.GetResponse();
                        Stream resStream = response.GetResponseStream();
                        string tempString = null;
                        int count = 0;
                        do
                        {
                            count = resStream.Read(buf, 0, buf.Length);
                            if (count != 0)
                            {
                                tempString = Encoding.ASCII.GetString(buf, 0, count);
                                sb.Append(tempString);
                            }
                        } while (count > 0);
                        if (sb.ToString().IndexOf("NOT ONLINE") == -1)
                        {
                            strStatus = "ONLINE";
                        }
                    }
                    catch (Exception)
                    {
                    }
                    return strStatus;
                }
                /// <summary>
                /// Tự động sinh thẻ img cho tài khoản Yahoo
                /// </summary>
                /// <param name="yahooID">Nick Yahoo</param>
                /// <param name="pathImageOnline">Ảnh nếu trạng thái ONLINE</param>
                /// <param name="pathImageOffline">Ảnh nếu trạng thái OFFLINE</param>
                /// <param name="alt">Thuộc tính alt cho thẻ img</param>
                /// <returns></returns>
                public static string WriteSupport(string yahooID, string pathImageOnline, string pathImageOffline,
                                                  string alt)
                {
                    string strTemp = "";
                    strTemp += "<a href='ymsgr:sendim?" + yahooID + "'>";
                    if (StatusSupport(yahooID) == "ONLINE")
                    {
                        strTemp += "<img title='" + alt + "' src='" + pathImageOnline + "' border='0' />";
                    }
                    else
                    {
                        strTemp += "<img title='" + alt + "' src='" + pathImageOffline + "' border='0' />";
                    }
                    strTemp += "</a>";
                    return strTemp;
                }
       }
       public class Skype
       {
            public static string AddScriptSkype()
            {
                    return
                        "<script type='text/javascript' src='http://www.skypeassets.com/i/scom/js/skype-uri.js'></script>";
            }
            public static string WriteSupport(string nick, string textTitle, string imageOnline, string imageOffline, string imageSize, bool flgChatOrCall = true, bool flgCheckStatus=true)
            {
                string tmp = "";
                string tmpChatOrCall = "chat";
                //Online;
                if(flgChatOrCall!=true)
                {
                    tmpChatOrCall = "call";
                }
                if (flgCheckStatus == true)
                {
                    if (Convert.ToInt16(StatusSupport(nick))==2 )
                    {
                        tmp += "<a href='skype:" + nick + "?" + tmpChatOrCall + "' rel='nofollow'><img style='width:" +
                               imageSize + "px;height:auto;' src='" + imageOnline + "' alt='" + textTitle + "' title='" +
                               textTitle + "'/></a>";
                    }
                    else //Offline;
                    {
                        tmp += "<a href='skype:" + nick + "?" + tmpChatOrCall + "' rel='nofollow'><img style='width:" +
                               imageSize + "px;height:auto;' src='" + imageOffline + "'  alt='" + textTitle +
                               "' title='" + textTitle + "'/></a>";
                    }
                }
                else//Mặc định ảnh online;
                {
                    tmp += "<a href='skype:" + nick + "?" + tmpChatOrCall + "' rel='nofollow'><img style='width:" +
                               imageSize + "px;height:auto;' src='" + imageOnline + "'  alt='" + textTitle +
                               "' title='" + textTitle + "'/></a>";
                }
                return tmp;
            }
            private static string StatusSupport(string SkypeID)
            {
                StringBuilder sb = new StringBuilder();
                byte[] buf = new byte[8192];
                string url = "http://mystatus.skype.com/" + SkypeID + ".num";
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream resStream = response.GetResponseStream();
                string tempString = null;
                int count = 0;
                do
                {
                    count = resStream.Read(buf, 0, buf.Length);
                    if (count != 0)
                    {
                        tempString = Encoding.ASCII.GetString(buf, 0, count);
                        sb.Append(tempString);
                    }
                } while (count > 0);
                return sb.ToString();
            }
        }
}
C. Cách sử dụng: Để sử dụng ta chỉ cần gọi hàm WriteSupport, sau đóđưa vào các tham số cần thiết để hiển thị.
Support.Yahoo.WriteSupport("sanddesert88","Đường dẫn ảnh nếu Online", "Đường dẫn ảnh nếu Offline","40", "Cù Kim Ngọc");
Như vậy là về cơ bản bạn có thể dễ dàng kiểm tra trạng thái Yahoo và Skype rồi, công việc còn lại là viết mã như thế nào cho phù hợp với yêu cầu chức năng, thiết kế của mình.
Chúc bạn thành công ! Nếu có thắc mắc, bạn vui lòng để lại phản hồi để được hỗ trợ, chia sẻ nhé !
In "C#"

Comments

  1. Hoàng Minh say

    Cảm ơn Admin của bài viết rất rất nhiều. nếu không có bài viết và ví dụ cụ thể này thì tôi chẳng biết đến khi nào mới hiểu được cách dùng backgroundworker nữa. Cảm ơn rất nhiều

  2. say

    Bạn ơi, mình đang cần sample code như bạn đã hướng dẫn. Bạn có thể gửi cho mình mã nguồn trong bài viết không ? mình đang cần tìm hiểu. Thank bạn.

    • say

      Hi bạn,
      Mình xin lỗi vì không cập nhật link trong bài viết sau lần đăng ký Google AdSense. Hiện tại mình vừa cập nhật lại link download source sample trong bài viết rồi, bạn có thể tải về nhé !
      P/s: Trong phần mô tả hướng dẫn của Video trên Youtube mình cũng có chia sẽ link download trước đây rồi bạn nhé !
      Cảm ơn bạn đã quan tâm chia sẻ !

      • say

        File của bạn m chạy bị lỗi
        Cross-thread operation not valid: Control ‘txtKetQua’ accessed from a thread other than the thread it was created on.
        (thread đang chạy đang thay đổi nội dung của thread khác nên ko cho sửa), vậy làm sao b

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.