background thread에서 수행하고 있는 task에 대해 새 창에서 진행률을 보여주려면 UI thread로 해당 부분을 넘겨줘야 한다.
그러려면 BackgroundWorker와 Dispatcher가 필요하다.
아래 코드는 기본적인 로직만 담고 있다. 필요한 경우에 가져다 쓰면 된다.
// MainWindow.xaml
<Window x:Class="TestProgress.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:TestProgress"
mc:Ignorable="d"
Title="테스트" Height="450" Width="800">
<Grid>
<Button Content="작업 시작" Click="StartButton_Click"/>
</Grid>
</Window>
// TestProgress.xaml.cs (Main Window)
namespace TestProgress
{
public partial class MainWindow : Window
{
private BackgroundWorker Worker;
private ProgressWindow ProgressBarWindow;
public MainWindow()
{
InitializeComponent();
}
private void StartButton_Click()
{
Worker = new()
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true // optional
};
Worker.DoWork += Worker_RunTask;
Worker.ProgressChanged += Worker_ProgressChanged;
Worker.RunWorkerCompleted += Worker_RunCompleted; // optional
Dispatcher.Invoke(() =>
{
ProgressBarWindow = new();
ProgressBarWindow.Show();
});
Worker.RunWorkerAsync();
}
private void Worker_RunTask(object sender, DoWorkEventArgs e)
{
int processedCount = 0;
foreach (string file in selectedFiles) // 어떤 형태든 반복문
{
// 취소 버튼 클릭 시 중단
if (cropWorker.CancellationPending)
{
e.Cancel = true;
return;
}
// 원하는 작업 수행
// 진행률 업데이트
processedCount++;
int progress = (int)((double)processedCount / selectedFiles.Length * 100);
(sender as BackgroundWorker).ReportProgress(progress);
}
}
// 작업 진행률 업데이트
private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ProgressBarWindow.UpdateProgress(e.ProgressPercentage);
}
// 작업 완료 시 수행할 것
private void Worker_RunCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Dispatcher.Invoke(() => {
ProgressBarWindow.Close();
});
MessageBox.Show("작업이 완료되었습니다.");
}
public void CancelTask()
{
Worker.CancelAsync();
}
}
// ProgressWindow.xaml
<Window x:Class="TestProgress.ProgressWindow"
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:TestProgress"
mc:Ignorable="d"
Title="작업 중..." Height="150" Width="450">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Center">
<ProgressBar x:Name="progressBar" Minimum="0" Maximum="100" Height="20" Width="410" Margin="20 25" VerticalAlignment="Top" HorizontalAlignment="Center" Visibility="Visible" />
<TextBlock Name="progressBarText" Text="{Binding ElementName=progressBar, Path=Value, StringFormat={}{0:0} %}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="-232"/>
</StackPanel>
<Button Grid.Row="0" Grid.Column="0" x:Name="cancelButton" Content="작업 취소" Margin="20 12" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="80" Height="35" Click="CancelButton_Click" />
</Grid>
</Window>
// ProgressWindow.xaml.cs
using System.ComponentModel;
using System.Windows;
namespace AutomatedTrainingSystem
{
public partial class ProgressWindow : Window
{
public ProgressWindow()
{
InitializeComponent();
}
public void UpdateProgress(int value)
{
Dispatcher.Invoke(() => progressBar.Value = value);
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
(Application.Current.MainWindow as MainWindow)?.CancelTask();
}
}
}
반응형