2

我有一个应用程序可以解析大型 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();

这行得通,但我有时会得到一个 ThreadAbortException on progressDialogThread.Start(),此时应该再次解析 XML。

有谁知道“关闭”进度对话框的更好方法?

由于控件必须建立在主 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>
4

2 回答 2

5

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

如果你想关闭一个Window,你调用Close它。

哦,它是由另一个线程创建的?好吧,这就是为什么你使用Window了一个,它会在那个线程上运行回调。DispatcherBeginInvoke

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

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

于 2019-06-01T11:29:57.663 回答
2

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

于 2019-06-01T11:14:03.667 回答