C# 在长时间运行的流程中,使用ReactiveUI、Observables、SubscribeOn和ObserveOn在UI中显示输出日志

C# 在长时间运行的流程中,使用ReactiveUI、Observables、SubscribeOn和ObserveOn在UI中显示输出日志,c#,.net,wpf,multithreading,system.reactive,C#,.net,Wpf,Multithreading,System.reactive,我有一个WPF应用程序,它将启动一个长时间运行的任务(60秒以上),该任务使用System.Reactive.Subject定期推送状态消息。当时的想法是,我可以从我的ViewModel订阅observable,并让ReactiveUI通过数据绑定自动更新我的UI。除了文本框没有实时更新之外,这一切都可以正常工作。它仅在长时间运行的任务完成后更新。我想这是因为我的UI线程被阻止,无法更新 在这种假设下,我的研究表明,我可以使用SubscribeOn将订阅放在后台线程上,然后使用ObserveOn

我有一个WPF应用程序,它将启动一个长时间运行的任务(60秒以上),该任务使用
System.Reactive.Subject
定期推送状态消息。当时的想法是,我可以从我的ViewModel订阅observable,并让ReactiveUI通过数据绑定自动更新我的UI。除了文本框没有实时更新之外,这一切都可以正常工作。它仅在长时间运行的任务完成后更新。我想这是因为我的UI线程被阻止,无法更新

在这种假设下,我的研究表明,我可以使用
SubscribeOn
将订阅放在后台线程上,然后使用
ObserveOnDispatcher
将通知推回到UI线程。然而,这仍然没有产生我想要的结果——UI只是在长时间运行的任务返回后才更新

有人能告诉我需要做些什么来实时更新输出日志吗?下面是相关的代码片段

XAML:

视图模型:

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}");
        }
公共主题输出{get;}
输出=新主题()//内导体
私有void PrintReplacement(XAttribute属性,字符串oldValue,字符串newValue,int级别,Verbosity minVerbosity=Verbosity.information)
{
if(Verbosity{newValue}{Environment.NewLine}”);
}

将我的长时间运行的任务函数调用封装在
等待任务中会有帮助吗?我在抓救命稻草。我对.NET线程没有很好的工作知识。

您使用的是主题,所以
.SubscribeOn(NewThreadScheduler.Default)
什么都不做。(标准的旧式击鼓)不要使用主题

长时间运行的进程应该是返回
IObservable
(而不是具有公开属性的类)的方法调用。
T
应该是您想要接收的状态更新。当任务完成时,你就完成了。如果任务失败,您将返回错误

理想情况下,使用Observable.Create返回IObservable的方法可以定义需要完成的工作

public IObservable<string> Convert()
{
    return Observable.Create<string>(observer=>
    {
        //do stuff here.
        //Call observer.OnNext with status messages
        //When done call observer.OnCompleted()
    });
}
public IObservable Convert()
{
返回可观察的。创建(观察者=>
{
//在这里做事。
//使用状态消息调用observer.OnNext
//完成后,调用observer.OnCompleted()
});
}

由于您没有说明长期运行的任务是什么,我无法再帮助您实施。

感谢您的回复。这是非常有趣的,可能真的有助于展示我对反应式的最基本的理解。你介意进一步说明为什么使用主题是不好的吗?我的理解是,“Subject”只是一个对象,它提供了“IObservable”和“IObserver”的标准实现。我想使用一个主题,因为我有几个“Print-”方法,它们都在调用“Output.OnNext”。我没有意识到这很重要,否则我会把它包括在问题中。我不确定使用“Observable.Create”时,该模式将如何工作
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}");
        }
public IObservable<string> Convert()
{
    return Observable.Create<string>(observer=>
    {
        //do stuff here.
        //Call observer.OnNext with status messages
        //When done call observer.OnCompleted()
    });
}