Я новичок в 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. Я не думаю, что это важно, но на всякий случай ...





Никогда не возвращайте 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, я бы дал вам рабочий код.
Теперь, чтобы аккуратно закрыть приложение, вы должны избавиться от всех создаваемых подписок, но, по крайней мере, вы больше не будете связывать поток в бесконечном цикле.
Из соображений простоты мы всегда могли упростить его до Thread.Sleep(3000); o.onNext("newParam");.
Observable.Generate очень мощный. Его нужно изучать и использовать вместо Observable.Create, где это возможно.
Спасибо за ответ! Фактически, «операции» - это чтение и анализ нескольких файлов в файловой системе. В зависимости от содержимого этих файлов наблюдатель может отправить новый параметр в ViewModel, чтобы он мог обновить пользовательский интерфейс.