Threadabortexception при вызове showdialog в C # - PullRequest
2 голосов
/ 01 июня 2019

У меня есть приложение, которое анализирует большой файл XML и создает элементы управления пользовательского интерфейса WPF на основе этого содержимого. Эта задача обычно занимает около 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 на progressDialogThread.Start(), когда XML должен быть проанализирован еще раз.

Кто-нибудь знает лучший способ «закрыть» диалог прогресса?

Поскольку элементы управления должны быть встроены в основной поток пользовательского интерфейса, я не могу использовать фонового рабочего ...

Сам диалог прогресса в 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>

Ответы [ 2 ]

5 голосов
/ 01 июня 2019

Не прерывайте поток, которого следует избегать.

Если вы хотите закрыть Window, вы вызываете Close для него.

О, он создаетсядругая нить?Хорошо, именно поэтому Window имеет Dispatcher, вы используете BeginInvoke, и он будет выполнять обратный вызов в этом потоке.

На самом деле, есть шанс, что вам не нужно создаватьWindow в другой теме ※.Вы можете создать его в основном потоке и заставить фоновый поток взаимодействовать с ним через BeginInvoke.

※: если основной поток занят и вы хотите Window в другом потоке, то основной поток выполняетне блокируйте его (или наоборот), вы, вероятно, должны использовать BackgroundWorker (как Кай Джард предлагает ) вместо того, чтобы поток пользовательского интерфейса был занят.

2 голосов
/ 01 июня 2019

Подобные вещи - именно то, для чего предназначен BackgroundWorker, и почему он знает разницу между потоком пользовательского интерфейса и рабочим потоком.Используйте фонового работника, проанализируйте ваш XML-файл в обработчике событий DoWork (он будет выполняться в фоновом потоке) и регулярно сообщайте о прогрессе, используя метод ReportProgress, проходя через цикл DoWork.Код обработчика ProgressChanged будет выполняться в потоке пользовательского интерфейса, и он должен нажать на диалоговое окно прогресса, чтобы предоставить обновление статуса процесса

...