У меня есть приложение WPF, которое запустит долговременную задачу (60 секунд), которая использует System.Reactive.Subject<string>
для изменения статуса сообщений. Идея заключалась в том, что я мог бы затем Подписываться на наблюдаемый из моего ViewModel и иметь ReactiveUI автоматически обновлять свой интерфейс через привязку данных. Все это прекрасно работает, за исключением того, что TextBox не обновляется в режиме реального времени. Он обновляется только после завершения долговременной задачи. Я предполагаю, что это связано с тем, что мой поток пользовательского интерфейса блокируется и не может обновляться.Использование ReactiveUI, Observables, SubscribeOn и ObserveOn для отображения журнала вывода в пользовательском интерфейсе во время долговременного процесса
Работая в соответствии с этим предположением, в моем исследовании было предложено разместить подписку на фоновом потоке с использованием SubscribeOn
, а затем направить уведомления обратно на поток пользовательского интерфейса, используя ObserveOnDispatcher
. Тем не менее, это все еще не привело к результатам, которые я хотел - пользовательский интерфейс обновлялся только после долговременной задачи.
Может ли кто-нибудь дать мне некоторое представление о том, что мне нужно сделать, чтобы мой журнал регистрации обновлялся в реальном времени? Ниже приведены соответствующие фрагменты кода.
XAML:
<TextBox Grid.Row="1" Text="{Binding Output}" IsReadOnly="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Margin="10,0,10,10" x:Name="OutputTextBox" />
Code-Behind:
protected override void OnContentRendered(EventArgs e)
{
if (Converter == null) return;
_viewModel = new ConversionOutputWindowViewModel(Converter);
DataContext = _viewModel;
_viewModel.StartConversion(); // Long-running Task
//_viewModel.StartSave();
FinishButton.IsEnabled = true;
}
ViewModel:
private string _output;
public string Output // Data bound in XAML
{
get { return _output; }
set { this.RaiseAndSetIfChanged(ref _output, value); }
}
public void StartConversion()
{
_edmxConverter.Convert(); // Long-running Task
}
public ConversionOutputWindowViewModel(Utilities.Converters.EdmxConverter converter)
{
_edmxConverter = converter;
_compositeDisposable.Add(_edmxConverter.Output
.SubscribeOn(NewThreadScheduler.Default)
.ObserveOnDispatcher()
.Subscribe(s => Output = Output += s));
//_compositeDisposable.Add(_edmxConverter.Output.Subscribe(s => Output = Output += s));
}
долгоиграющих Задача Функция:
public Subject<string> Output { get; }
Output = new Subject<string>(); //In ctor
private void PrintReplacement(XAttribute attribute, string oldValue, string newValue, int level, Verbosity minVerbosity = Verbosity.Informational)
{
if (Verbosity < minVerbosity) return;
Output.OnNext($"{new string('\t', level)}{attribute.Name}: {oldValue} -> {newValue}{Environment.NewLine}");
}
Возможно, это поможет обернуть мой вызов функции Long-running Task внутри await Task.Run
? Я хватаюсь за соломинку здесь. У меня нет хороших рабочих знаний о потоке .NET.
Спасибо за ответ. Это очень интересно и, вероятно, действительно служит для отображения моего очень рудиментарного понимания Reactive. Не могли бы вы объяснить, почему использование предметов плохо? Мое понимание заключалось в том, что «Subject» был просто объектом, который предоставлял стандартные реализации как «IObservable», так и «IObserver». Я хотел использовать тему, потому что у меня есть несколько методов «Печать», которые все вызывают «Output.OnNext (s)». Я не понимал, что это важно, иначе я бы включил его в вопрос. Я не уверен, как этот шаблон будет работать при использовании «Observable.Create» –
https://leecampbell.com/2016/10/03/iprogress-and-rx-without-subjects/ –