2018년 1월 29일 월요일

[WPF 실습예제] Background Worker를 이용한 WPF 멀티쓰레드 프로그래밍 실습

1.5.3 Background Worker를 이용한 WPF 멀티쓰레드 프로그래밍 실습

[간단히 Backgroud Worker를 사용한 예제를 작성해 보자.]
n  숫자를 입력하면 백그라운드 워커를 통해 ProgressBar에 진행 사항을 표시하고리스트 박스에 짝수들을 출력그리고 합을 구해 출력하는 예제이다.
n  1. BackgroundWorkerTest 하는 이름으로 WPF 프로젝트 생성
8190bc7e133861fca87082230a72e6b9_1517216
 


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 속성 “”)
 8190bc7e133861fca87082230a72e6b9_15172168190bc7e133861fca87082230a72e6b9_1517216 

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 != nullMessageBox.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();
        }
    }
}

댓글 없음:

댓글 쓰기