Head Frist c# 3rd Edition에 부록에 있는 Background worker 구현 (Progress bar update)
- Do work process
- Cancellation process
- report progress
1. 쓰레드로 구현하지 않을 경우 , Progress bar가 진행하는 동안 Main process를 접근 불가 (check를 하지 않고 실행)
2. 쓰레드와 Time.Sleep을 구현하는 방법 보다 간단함
[MainWindow.xml]
<Window x:Class="BackgroundWorkerTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BackgroundWorkerTest"
mc:Ignorable="d"
Title="Background Worker Example" Height="150" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<CheckBox Name="useBackgroundWorkerCheckbox" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center"></CheckBox>
<Label Grid.Column="1" Grid.ColumnSpan="2" Content="Use BackgroundWoker" HorizontalAlignment="Center" VerticalAlignment="Center"></Label>
<Button Name="goButton" Grid.Row="1" Grid.Column="0" Margin="3,3,3,3" Content="Go!" FontSize="10.667" Click="goButton_Click" IsEnabled="True"></Button>
<Button Name="cancelButton" Grid.Row="1" Grid.Column="1" Margin="3,3,3,3" Content="Cancel" FontSize="10.667" Click="cancelButton_Click" IsEnabled="True" ></Button>
<ProgressBar Grid.Row="2" Margin="3,3,3,3" Grid.ColumnSpan="3" Name="progressBar1"></ProgressBar>
</Grid>
</Window>
[MainWindow.xaml.cs]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace BackgroundWorkerTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly BackgroundWorker backgroundWorker1 = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
}
//ui event
private void goButton_Click(object sender, EventArgs e)
{
goButton.IsEnabled = false;
if (!useBackgroundWorkerCheckbox.IsChecked == true)
{
// If we're not using the background worker, just start wasting CPU cycles
for (int i = 1; i <= 100; i++)
{
WasteCPUCycles();
progressBar1.Value = i;
}
goButton.IsEnabled = true;
}
else {
// If the form's using the background worker, it enables the Cancel button.
cancelButton.IsEnabled = true;
// If we are using the background worker, use its RunWorkerAsync()
// to tell it to start its work
backgroundWorker1.RunWorkerAsync(new Guy("Bob", 37, 146));
}
}
/// <summary>
/// When the user clicks Cancel, call BackgroundWorker.CancelAsync() to send it a cancel message
/// </summary>
private void cancelButton_Click(object sender, EventArgs e)
{
// If the user clicks Cancel, it calls the BackgroundWorker's CancelAsync()
// method to give it the message to cancel.
backgroundWorker1.CancelAsync();
}
//background worker function
/// <summary>
/// The BackgroundWorker object runs its DoWork event handler in the background
/// </summary>
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// The e.Argument property returns the argument that was passed to RunWorkerAsync()
Console.WriteLine("Background worker argument: " + (e.Argument ?? "null"));
// Start wasting CPU cycles
for (int i = 1; i <= 100; i++)
{
WasteCPUCycles();
// Use the BackgroundWorker.ReportProgress method to report the % complete
backgroundWorker1.ReportProgress(i);
// If the BackgroundWorker.CancellationPending property is true, cancel
if (backgroundWorker1.CancellationPending)
{
Console.WriteLine("Cancelled");
break;
}
}
}
/// <summary>
/// BackgroundWorker fires its ProgressChanged event when the worker thread reports progress
/// </summary>
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
/// <summary>
/// BackgroundWorker fires its RunWorkerCompleted event when its work is done (or cancelled)
/// </summary>
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// When the work is complete, the RunWorkerCompleted event handler
// re-enables the Go! button and disables the Cancel button.
goButton.IsEnabled = true;
cancelButton.IsEnabled = false;
}
//other function
/// <summary>
/// Waste CPU cycles causing the program to slow down by doing calculations for 100ms
/// </summary>
private void WasteCPUCycles()
{
DateTime startTime = DateTime.Now;
double value = Math.E;
while (DateTime.Now < startTime.AddMilliseconds(100))
{
value /= Math.PI;
value *= Math.Sqrt(2);
}
}
/// <summary>
/// Clicking the Go button starts wasting CPU cycles for 10 seconds
/// </summary>
}
}