Ручная остановка отладки с помощью backgroundworker

Я пишу проект WPF С# с использованием BackgroundWorker (всплывающее окно с индикатором выполнения).

Я запускаю отладку (клавиша F5), чтобы проверить свою программу. После завершения BackgroundWorker и закрытия всплывающего окна закрытие MainWindow не останавливает автоматически процесс отладки. Мне приходится вручную нажимать Shift+F5, чтобы остановить отладку.

Я думал, что BackgroundWorker должен был позаботиться о теме автоматически. Но в любом случае я все еще вызываю backgroundworker.Dispose() и backgroundworker.CancelAsync() в методе RunWorkerCompleted. И тем не менее, после закрытия всплывающего окна и завершения BackgroundWorker мне все еще приходится вручную нажимать Shift+F5, чтобы остановить отладку.

Что происходит в фоновом режиме, чтобы программа не останавливала отладку автоматически? Как я могу узнать?

ПРИМЕЧАНИЕ. Я удостоверился, что фоновый рабочий процесс завершен, прежде чем я его закрою. Со всплывающим окном и BackgroundWorker он автоматически прекращает отладку в тот момент, когда я закрываю главное окно.

[ИЗМЕНИТЬ с кодами]

public partial class MainWindow : Window
{
    BackgroundWorker backgroundworker1 = new BackgroundWorker();

    PopUp pop1 = new PopUp();

public MainWindow()
{
    InitializeComponent();

    backgroundworker1.DoWork += BackgroundWorker_DoWork;
    backgroundworker1.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
    backgroundworker1.WorkerReportsProgress = true;
    backgroundworker1.ProgressChanged += BackgroundWorker_ProgressChanged;
    backgroundworker1.WorkerSupportsCancellation = true;
}

private void startBtn_Click(object sender, RoutedEventArgs e)
{
    pop1 = new PopUp();

    int iteration = 0;
    if (int.TryParse(iterationTb1.Text, out iteration))
    {
        pop1.Show();
        backgroundworker1.Dispose();
        backgroundworker1.RunWorkerAsync(iteration);
        outputTb1.Text = "running...";
    }
}

private void cancelBtn_Click(object sender, RoutedEventArgs e)
{
    pop1.Close();
    backgroundworker1.CancelAsync();
}

public static int DoSlowProcess(int iterations, BackgroundWorker worker, DoWorkEventArgs e)
{
    int result = 0;

    for (int i = 0; i <= iterations; i++)
    {
        if (worker != null)
        {
            if (worker.CancellationPending)
            {
                e.Cancel = true;
                return result;
            }
            if (worker.WorkerReportsProgress)
            {
                int percentComplete = (int)((float)i / (float)iterations * 100);
                worker.ReportProgress(percentComplete);
            }
        }

        Thread.Sleep(100);
        result = i;
    }

    return result;
}


private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    var bgw = sender as BackgroundWorker;
    e.Result = DoSlowProcess((int)e.Argument, bgw, e);
}

private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null)
    {
        MessageBox.Show(e.Error.Message);
    }
    else if (e.Cancelled)
    {
        outputTb1.Text = "Canceled";
    }
    else
    {
        outputTb1.Text = e.Result.ToString();
        backgroundworker1.CancelAsync();
        backgroundworker1.Dispose();
        pop1.Close();
        pop1.progressBar1.Value = 0;
    }
}

    private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        pop1.progressBar1.Value = e.ProgressPercentage;
        pop1.progressLb1.Content = e.ProgressPercentage.ToString();
    }
}

person KMC    schedule 14.08.2011    source источник
comment
Что-то поддерживает ваш процесс, и, вероятно, это не bgw.   -  person Henk Holterman    schedule 14.08.2011
comment
Это то, что я, хотя, но когда у меня нет фонового рабочего, он автоматически прекращает отладку. Как я могу узнать?   -  person KMC    schedule 14.08.2011
comment
Я согласен с Хенком, это, вероятно, не фоновый рабочий. Пока отладчик находится в этом состоянии, можете ли вы выполнить Break All и использовать окно Threads, чтобы увидеть, что делает каждый из потоков?   -  person JohnD    schedule 14.08.2011
comment
Я сделал Break All, и он отображается только в VS2010 No Source Available. Я не могу найти вызов окна Threads, есть окно IntelliTrace и Output, но они не предлагают ничего полезного.   -  person KMC    schedule 14.08.2011
comment
Доступ к окну Threads можно получить из меню отладки: Debug ›› Windows ›› Threads   -  person JohnD    schedule 14.08.2011
comment
Вы установили ShutdownMode в App? Если да, то к чему?   -  person svick    schedule 14.08.2011
comment
Вы имели в виду, что используете всплывающее окно, делали ли вы что-нибудь, чтобы предотвратить закрытие этого окна, например, отменив событие закрытия?   -  person Fredrik Hedblad    schedule 14.08.2011
comment
Чтобы добраться куда угодно, опубликуйте весь код, относящийся к отображению всплывающего окна и закрытию.   -  person Henk Holterman    schedule 14.08.2011
comment
Я опубликовал весь код в своем классе. Надеюсь, поможет. Спасибо.   -  person KMC    schedule 15.08.2011
comment
Окно отладки потоков можно найти в Debug|Windows при отладке.   -  person Mark Green    schedule 15.08.2011
comment
@kmc, после редактирования: никаких заметных проблем. Если вы запустите только это в новом проекте, он не закроется? Bgw.Dispose() выглядит ужасно, не используйте повторно что-либо после Dispose(). Но этот должен быть безвредным.   -  person Henk Holterman    schedule 15.08.2011
comment
Вот это я чувствую странно. Я специально не ищу ответ, если кто-нибудь и указать мне, как узнать мою проблему. Есть ли что-то, что я могу проверить, какой поток работает в фоновом режиме, помимо основного потока пользовательского интерфейса?   -  person KMC    schedule 15.08.2011


Ответы (1)


Хорошо, я смог воспроизвести вашу проблему, а также нашел причину.

Измените эту строку:

// PopUp pop1 = new PopUp();  <-- this never-used Win was blocking your close-down.
PopUp pop1 = null;

Потому что у вас также есть

pop1 = new PopUp();
int iteration = 0;

Создание объектов только для инициализации переменной и последующая перезапись ее всегда является антишаблоном. В этом случае это на самом деле вредно, потому что вы создаете окно, но никогда не показываете () или закрываете () его.

Обратите внимание, что фоновый рабочий не задействован. Этого не может быть, он использует ThreadPool, а это означает фоновые потоки. Вы можете закрыть приложение с несколькими фоновыми рабочими процессами без проблем.

person Henk Holterman    schedule 15.08.2011