This.Close () не убивает поток, созданный наблюдателем NewThreadScheduler.Default.Schedule

Я новичок в C#, и у меня возникла следующая проблема: у меня есть приложение WPF, которое выполняет бесконечную задачу, которая выполняет довольно дорогостоящие фоновые операции. Эти операции могут иногда изменять значение, и его необходимо обновлять в пользовательском интерфейсе. Операции должны выполняться в потоке, отличном от потока пользовательского интерфейса, поскольку они могут заблокировать пользовательский интерфейс. Итак, я пытаюсь использовать библиотеку System.Reactive, и она на самом деле работает очень хорошо ... но когда я пытаюсь закрыть приложение с помощью настраиваемой кнопки закрытия, которая выполняет метод this.Close();, приложение не закрывается.

Моя наблюдаемая выглядит примерно так:

internal IObservable<string> DoBackgroundOperations(string param) {

    return Observable.Create<string>(o => {
        NewThreadScheduler.Default.Schedule(() => {
            for (;;) {
                param = // some operations that change the param

                // when the param has been changed, I send the new value to the subscribers
                o.OnNext(param);
            }
        });

        return Disposable.Empty;
    });
}

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

sevice.DoBackgroundOperations(param).Subscribe(newVal => Data = newVal);

Как я уже сказал, я получаю обновленные значения, когда они приходят, и все работает нормально, но когда срабатывает событие щелчка кнопки закрытия, окно пользовательского интерфейса «исчезает», но само приложение никогда не закрывается. Я думаю, что поток, созданный наблюдаемым, поддерживает работу приложения.

Итак, мой вопрос: как я могу правильно закрыть приложение и предотвратить его сохранение в потоке?

Спасибо!

Редактировать

Я использую caliburn.micro для реализации паттерна MVVM. Я оформляю подписку в одном из моих классов ViewModel. Я не думаю, что это важно, но на всякий случай ...

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Никогда не возвращайте Disposable.Empty. Вы вынуждены делать это, потому что в вашем коде нет естественного одноразового элемента, в свою очередь, потому что вы создаете бесконечный цикл.

Избавьтесь от бесконечного цикла, и вы сможете решить всю проблему.

Вы можете решить это просто так:

internal IObservable<string> DoBackgroundOperations(string param)
{
    return
        Observable
            .Generate(
                0,
                x => true,
                x => x + 1,
                x => /* some operations that change the param */,
                Scheduler.Default);
}

Я специально выбрал Scheduler.Default, потому что Scheduler.NewThread устарел.

Если бы вы предоставили код для // some operations that change the param, я бы дал вам рабочий код.

Теперь, чтобы аккуратно закрыть приложение, вы должны избавиться от всех создаваемых подписок, но, по крайней мере, вы больше не будете связывать поток в бесконечном цикле.

Спасибо за ответ! Фактически, «операции» - это чтение и анализ нескольких файлов в файловой системе. В зависимости от содержимого этих файлов наблюдатель может отправить новый параметр в ViewModel, чтобы он мог обновить пользовательский интерфейс.

Lucas Colombo 17.12.2018 11:43

Из соображений простоты мы всегда могли упростить его до Thread.Sleep(3000); o.onNext("newParam");.

Lucas Colombo 17.12.2018 11:45
Observable.Generate очень мощный. Его нужно изучать и использовать вместо Observable.Create, где это возможно.
Enigmativity 17.12.2018 11:51

Другие вопросы по теме