我有一个解析大型XML文件并基于该内容构建WPF UI控件的应用程序。此任务通常需要大约15-30秒。为了通知用户正在运行的任务,我显示了一个简单的中间进度对话框窗口,例如:
Thread progressDialogThread = new Thread(() =>
{
Window window = new Window
{
Content = new ProgressDialog(),
Height = 100,
Width = 150,
WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen
};
window.ShowDialog();
});
progressDialogThread.SetApartmentState(ApartmentState.STA);
progressDialogThread.IsBackground = true;
progressDialogThread.Start();
buildUI();
progressDialogThread.Abort();
这行得通,但是当应该再次解析XML时,我有时在progressDialogThread.Start()
上收到ThreadAbortException。
有人知道更好的“关闭”进度对话框的方法吗?
由于控件必须构建在主UI线程上,因此我不能使用backgroundworker ...
XAML中的进度对话框本身看起来像:
<UserControl x:Class="MyDialog.ProgressDialog"
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:MyDialog"
mc:Ignorable="d"
Background="{DynamicResource MaterialDesignPaper}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
Height="100" Width="150">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Label HorizontalAlignment="Center">Please wait</Label>
<ProgressBar
Style="{StaticResource MaterialDesignCircularProgressBar}"
Value="0"
IsIndeterminate="True" Width="40" Height="41" Margin="55,0" HorizontalAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</UserControl>
答案 0 :(得分:5)
请勿中止线程,这应该避免。
如果要关闭Window
,请在其上调用Close
。
哦,它是由另一个线程创建的吗?好吧,这就是Window
拥有Dispatcher
的原因,您使用BeginInvoke
它将在该线程上运行回调。
实际上,您有可能不需要在另一个线程中创建Window
※。您可以在主线程中创建它,并让后台线程通过BeginInvoke
与之交互。
※:如果您的主线程忙,并且希望将Window
放在另一个线程中,以便主线程不会阻塞它(反之亦然),则您可能应该使用BackgroundWorker
(如{ {3}}),而不是让UI线程忙。
答案 1 :(得分:2)
像这样的事情正是BackgroundWorker的目的,以及为什么它知道UI线程和工作线程之间的区别。使用后台工作程序,在DoWork事件处理程序中解析您的XML文件(它将在后台线程上运行),并在继续执行DoWork循环时使用ReportProgress方法定期报告进度。 ProgressChanged处理程序代码将在UI线程上执行,并且应戳开进度对话框以提供进程的状态更新