본문 바로가기

C#

c# winform backgroundworker 스레드 중단/재개하기 코드

c# winform background worker에서 중요한 점은

background worker에서 do_work는 별도의 background 스레드에서 동작하기 때문에 UI를 손볼 수 없다.

ui의 변경은 ProgressChangedEventHandler나 RunWorkCompletedEventHandler에서 조정한다.

또한 background worker의 중단/재개 방법을 코드로 적는다.

버튼으로 중단/재개를 할 수 있으며, P(중단) R(재개) 키를 누름으로서 프로그램의 중단/재개를 할 수 있다.

 

======= 코드 =======

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
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;
using System.Diagnostics;
using System.Threading;
 
namespace WinFormsApp5
{
    public partial class Form1 : Form
    {
        private BackgroundWorker worker;
        private ManualResetEvent _pauseEvent = new ManualResetEvent(true);
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Pause()
        {
            _pauseEvent.Reset();
        }
 
        private void Resume()
        {
            _pauseEvent.Set();
        }
 
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            switch (keyData)
            {
                case Keys.P:
                    Debug.WriteLine("Pause(P) key button is pressed");
                    Pause();
                    break;
                case Keys.R:
                    Debug.WriteLine("Resume(R) key button is pressed");
                    Resume();
                    break;
            }
            return base.ProcessCmdKey(ref msg, keyData);
       }
        
 
        private void button1_Click(object sender, EventArgs e)
        {
            worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.WorkerSupportsCancellation = true;
            // worker_DoWork가 별도의 백그라운드 스레드임
            // worker_ProgressChanged와 worker_RunWorkerCompleted는 UI 스레드에서 돌아감
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
 
            worker.RunWorkerAsync();
            button1.Enabled = false;            
        }
        
        private void worker_DoWork(object sender,
            DoWorkEventArgs e)
        {
            int N = 100;
            for (int i=1; i <= N; i++)
            {
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }
                // P 버튼을 누르면 Stop
                // R 버튼을 누르면 Resume
                _pauseEvent.WaitOne();
                string filename = "Data_" + i + ".txt";
                Upload(filename);
                worker.ReportProgress(i, filename);
            }
        }
 
        void Upload(string filename)
        {
            Debug.WriteLine("Uploading " + filename);
            Thread.Sleep(1000);
        }
 
        void worker_ProgressChanged(object sender,
            ProgressChangedEventArgs e)
        {
            if (_pauseEvent.WaitOne(0))
            { label1.Text = string.Format("Progress : {0} %", e.ProgressPercentage); }
        }
 
        void worker_RunWorkerCompleted(object sender,
            RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                label1.Text = "작업 취소됨";
            }
            else if (e.Error != null)
            {
                throw e.Error;
            }
            else
            {
                label1.Text = string.Format("{0} files updated", e.Result);
            }
        }
 
        private void CancelButton_Click(object sender, EventArgs e)
        {
            worker.CancelAsync();
        }
 
        private void StopButton_Click(object sender, EventArgs e)
        {
            if (_pauseEvent.WaitOne(0))
            {
                Pause();
                label1.Text = "업데이트가 잠시 중단되었습니다.";
            }
        }
 
        private void ResumeButton_Click(object sender, EventArgs e)            
        {
            label1.Text = "업데이트가 재개되었습니다.";
            Resume();
        }
    }
}
 
cs

 

'C#' 카테고리의 다른 글

c# winform 특정 시간마다 thread 실행하기 코드  (0) 2021.11.07
c# winform timer  (0) 2021.11.07
c# winform chart(only for .net framework)  (0) 2021.11.06
c# winform listview  (0) 2021.11.05
c# winform drag & drop  (0) 2021.11.05