본문 바로가기
📁 [4] 개발자 정보 & 코드 노트/C#

C# Windows Forms 강의 105편: 멀티스레드 데이터 처리와 UI 갱신 (BackgroundWorker 활용)

by wawManager 2025. 5. 19.

 

1. 강의 개요

이번 강의에서는 멀티스레드를 활용하여 대량의 데이터를 처리하면서도 UI의 응답성을 유지하는 방법을 학습합니다.
Windows Forms에서는 기본적으로 UI 스레드에서 모든 작업이 실행되기 때문에,
대량의 데이터를 처리하면 UI가 멈추거나 응답하지 않는 문제가 발생할 수 있습니다.

이 강의에서는 BackgroundWorker를 활용하여 UI를 멈추지 않고 백그라운드에서 데이터를 처리하는 방법을 배웁니다.


2. 학습 목표

✅ 멀티스레드 개념 이해 및 UI 스레드와의 차이점 학습
✅ BackgroundWorker를 활용한 백그라운드 데이터 처리 구현
✅ UI를 멈추지 않고 ProgressBar를 활용한 진행률 표시


3. 기능 요구사항

🟢 필수 기능

1️⃣ 백그라운드 데이터 처리

  • 무거운 작업(예: 100만 개 데이터 처리)을 백그라운드에서 실행

2️⃣ 진행률 표시

  • ProgressBar를 통해 작업 진행 상황을 실시간으로 UI에 표시

3️⃣ UI 응답성 유지

  • 작업이 실행되는 동안에도 버튼 클릭 및 다른 UI 요소 사용 가능

4. 실습: 멀티스레드 데이터 처리 및 UI 갱신 구현

1️⃣ 폼 구성

  • 폼(Form) 이름: Form1
  • 컨트롤 배치:

컨트롤 타입 이름 위치 크기

Button btnStart 상단 (150 x 40)
ProgressBar progressBar 중앙 (300 x 30)
Label lblStatus 하단 (300 x 30)

📌 폼 디자인 예시:

------------------------------------------------
| [        btnStart (작업 시작)              ] |
| [  progressBar (작업 진행률 표시)         ] |
| [ lblStatus (현재 상태)                   ] |
------------------------------------------------

2️⃣ 코드 작성

(1) BackgroundWorker를 활용한 백그라운드 데이터 처리

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApp_MultiThread
{
    public partial class Form1 : Form
    {
        private BackgroundWorker backgroundWorker;

        public Form1()
        {
            InitializeComponent();
            InitializeBackgroundWorker();
        }

        // BackgroundWorker 초기화
        private void InitializeBackgroundWorker()
        {
            backgroundWorker = new BackgroundWorker();
            backgroundWorker.WorkerReportsProgress = true;
            backgroundWorker.WorkerSupportsCancellation = true;

            backgroundWorker.DoWork += BackgroundWorker_DoWork;
            backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
            backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
        }

        // 버튼 클릭 시 작업 시작
        private void btnStart_Click(object sender, EventArgs e)
        {
            if (!backgroundWorker.IsBusy)
            {
                progressBar.Value = 0;
                lblStatus.Text = "작업 시작...";
                backgroundWorker.RunWorkerAsync();
            }
        }

        // 백그라운드에서 실행할 무거운 작업
        private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 1; i <= 100; i++)
            {
                if (backgroundWorker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                Thread.Sleep(50); // 가상 작업 (50ms 딜레이)
                backgroundWorker.ReportProgress(i); // 진행률 업데이트
            }
        }

        // 작업 진행률 UI 업데이트
        private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar.Value = e.ProgressPercentage;
            lblStatus.Text = $"진행률: {e.ProgressPercentage}%";
        }

        // 작업 완료 시 호출
        private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                lblStatus.Text = "작업 취소됨";
            }
            else
            {
                lblStatus.Text = "작업 완료!";
            }
        }
    }
}

(2) Designer 코드

        private void InitializeComponent()
        {
            this.btnStart = new Button();
            this.progressBar = new ProgressBar();
            this.lblStatus = new Label();

            // 버튼 설정
            this.btnStart.Location = new System.Drawing.Point(10, 10);
            this.btnStart.Size = new System.Drawing.Size(150, 40);
            this.btnStart.Text = "작업 시작";
            this.btnStart.Click += new EventHandler(this.btnStart_Click);

            // ProgressBar 설정
            this.progressBar.Location = new System.Drawing.Point(10, 60);
            this.progressBar.Size = new System.Drawing.Size(300, 30);

            // Label 설정
            this.lblStatus.Location = new System.Drawing.Point(10, 100);
            this.lblStatus.Size = new System.Drawing.Size(300, 30);
            this.lblStatus.Text = "대기 중...";

            // Form 설정
            this.ClientSize = new System.Drawing.Size(330, 150);
            this.Controls.Add(this.btnStart);
            this.Controls.Add(this.progressBar);
            this.Controls.Add(this.lblStatus);
            this.Text = "멀티스레드 데이터 처리";
        }

3️⃣ 실행 결과

UI가 멈추지 않고 백그라운드에서 데이터 처리

  • "작업 시작" 버튼 클릭 → ProgressBar가 증가하며 UI가 정상적으로 작동

진행률이 실시간으로 표시됨

  • 작업이 진행되면서 Label과 ProgressBar가 업데이트됨

작업 완료 시 상태 메시지 변경

  • 100% 완료 시 "작업 완료!" 메시지 표시

5. 주요 개념 요약

  • BackgroundWorker: Windows Forms에서 백그라운드 작업을 수행하는 비동기 처리 도구
  • WorkerReportsProgress: true 설정 시 진행률 보고 가능
  • WorkerSupportsCancellation: true 설정 시 작업 취소 가능
  • DoWork 이벤트: 백그라운드에서 실행할 무거운 작업 정의
  • ProgressChanged 이벤트: UI에 진행률 업데이트
  • RunWorkerCompleted 이벤트: 작업이 완료되었을 때 실행

📌 #CSharp #WindowsForms #멀티스레드 #BackgroundWorker #UI응답성유지