在 C# 中调用 showdialog 时出现 Threadabortexception

Threadabortexception when calling showdialog in C#

我有一个应用程序可以解析大型 XML 文件并基于该内容构建 WPF UI 控件。此任务通常需要大约 15 - 30 秒。为了通知用户 运行 任务,我显示一个简单的中间进度对话框 window,例如:

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();

这行得通,但我有时会在 progressDialogThread.Start() 上遇到 ThreadAbortException,此时应再次解析 XML。

有人知道 "close" 进度对话框的更好方法吗?

由于控件必须建立在主UI线程上,我不能使用后台程序...

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>

像这样的事情正是 BackgroundWorker 的用途,以及为什么它知道 UI 线程和工作线程之间的区别。使用后台工作者,在 DoWork 事件处理程序中解析您的 XML 文件(它将在后台线程上 运行 )并在执行 DoWork 循环时使用 ReportProgress 方法定期报告进度。 ProgressChanged 处理程序代码将在 UI 线程上执行,它应该弹出进度对话框以提供有关进程的状态更新

不要中止线程,应该避免这种情况。

如果你想关闭一个 Window,你可以在上面调用 Close

哦,是别的线程创建的?好吧,这就是 Window 有一个 Dispatcher 的原因,你使用 BeginInvoke 它将 运行 在该线程上的回调。

事实上,您有可能不需要在另一个线程中创建 Window※。您可以在主线程中创建它并让后台线程通过 BeginInvoke.

与其交互

※:如果你的主线程很忙并且想要在另一个线程中使用 Window 这样主线程就不会阻塞它(反之亦然),你可能应该使用 BackgroundWorker (作为 ) 而不是让 UI 线程忙。