1.5.3 Background Worker를 이용한 WPF 멀티쓰레드 프로그래밍 실습
[간단히 Backgroud Worker를 사용한 예제를 작성해 보자.]
n 숫자를 입력하면 백그라운드 워커를 통해 ProgressBar에 진행 사항을 표시하고, 리스트 박스에 짝수들을 출력, 그리고 합을 구해 출력하는 예제이다.
n 1. BackgroundWorkerTest 하는 이름으로 WPF 프로젝트 생성
n MainWindow.xaml 파일을 더블클릭 후 디자인 화면에서 아래와 같이 디자인 하자.
- Label (Content 속성 : “숫자를 입력하세요”)
- TextBox (Name 속성 : txtNumber, Text 속성 : “”)
- Button(Name 속성 : btnStart, Text 속성 : “실행”)
- Button(Name 속성 : btnCancel, Text 속성 : “중단”)
- ProgressBar(Name 속성 : progressBar)
- ListBox(Name 속성 : lstNumber)
- Label(Content 속성 : “합계는”)
- TextBlock(Name 속성 : tblkSum, Text 속성 “”)
n MainWindow.xaml.cs
<Window x:Class="BackgroundWorkerTest.MainWindow"
xmlns:local="clr-namespace:BackgroundWorkerTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="359.844">
<Grid>
<Label Content="숫자를 입력하세요." HorizontalAlignment="Left" Margin="44,25,0,0"VerticalAlignment="Top" Width="121"/>
<TextBox x:Name="txtNumber" HorizontalAlignment="Left" Height="23"Margin="170,29,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="54"/>
<Button x:Name="btnStart" Content="실행" HorizontalAlignment="Left"Margin="235,29,0,0" VerticalAlignment="Top" Width="44" Height="23" Click="btnStart_Click"/>
<Button x:Name="brnCancel" Content="중단" HorizontalAlignment="Left"Margin="284,29,0,0" VerticalAlignment="Top" Width="41" Height="23"Click="btnCancel_Click"/>
<ProgressBar x:Name="progressBar" HorizontalAlignment="Left" Height="18"Margin="57,80,0,0" VerticalAlignment="Top" Width="268"/>
<ListBox x:Name="lstNumber" HorizontalAlignment="Left" Height="174"Margin="57,125,0,0" VerticalAlignment="Top" Width="100"/>
<Label Content="합계는 ?" HorizontalAlignment="Left" Margin="194,125,0,0"VerticalAlignment="Top" Width="108"/>
<TextBlock x:Name="tblkSum" HorizontalAlignment="Left" Margin="202,151,0,0"TextWrapping="Wrap" VerticalAlignment="Top" Width="77" Height="20" Foreground="#FFFAF8F8">
<TextBlock.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="#FFB1A5A5" Offset="1"/>
</LinearGradientBrush>
</TextBlock.Background>
<TextBlock.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</TextBlock.OpacityMask>
</TextBlock>
</Grid>
</Window>
n MainWindow.xaml.cs
using System;
using System.ComponentModel;
using System.Windows;
using System.Threading;
using System.Windows.Threading;
namespace BackgroundWorkerTest
{
public partial class MainWindow : Window
{
//백그라운드 워커 선언
private BackgroundWorker myThread;
//짝수의 합을 저장할 인스턴스 변수
int sum = 0;
public MainWindow()
{
InitializeComponent();
}
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
//백그라운드 워커 초기화
//작업의 진행율이 바뀔때 ProgressChanged 이벤트 발생여부
//작업취소 가능여부 true로 설정
myThread = new BackgroundWorker()
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
//백그라운드에서 실행될 콜백 이벤트 생성
//For the performing operation in the background.
//해야할 작업을 실행할 메소드 정의
myThread.DoWork += myThread_DoWork;
//UI쪽에 진행사항을 보여주기 위해
//WorkerReportsProgress 속성값이 true 일때만 이벤트 발생
myThread.ProgressChanged += myThread_ProgressChanged;
//작업이 완료되었을 때 실행할 콜백메소드 정의
myThread.RunWorkerCompleted += myThread_RunWorkerCompleted;
MessageBox.Show("Worker 초기화");
}
//백그라운드 워커가 실행하는 작업
//DoWork 이벤트 처리 메소드에서 lstNumber.Items.Add(i) 와 같은 코드를
//직접 실행시키면 "InvalidOperationException" 오류발생
private void myThread_DoWork(object sender, DoWorkEventArgs e)
{
int count = (int)e.Argument;
for (int i = 1; i <= count ; i++)
{
if (myThread.CancellationPending)
{
e.Cancel = true;
return;
}
else
{
Thread.Sleep(100);
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate ()
{
if (i % 2 == 0)
{
sum += i;
e.Result = sum;
lstNumber.Items.Add(i);
}
}
);
myThread.ReportProgress(i);
}
}
}
//작업의 진행률이 바뀔때 발생, ProgressBar에 변경사항을 출력
//대체로 현재의 진행상태를 보여주는 코드 여기에 작성.
private void myThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
//작업완료
private void myThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgse)
{
if (e.Cancelled) MessageBox.Show("작업 취소...");
else if (e.Error != null) MessageBox.Show("에러발생..." + e.Error);
else
{
tblkSum.Text = ((int)e.Result).ToString();
MessageBox.Show("작업 완료!!");
}
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
int num;
if (!int.TryParse(txtNumber.Text, out num))
{
MessageBox.Show("숫자를 입력하세요.!");
return;
}
progressBar.Maximum = num;
lstNumber.Items.Clear();
myThread.RunWorkerAsync(num);
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
myThread.CancelAsync();
}
}
}
댓글 없음:
댓글 쓰기