Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用带有ReactiveUI的异步API填充集合的最佳方法是什么?_C#_Asynchronous_System.reactive_Reactiveui - Fatal编程技术网

C# 使用带有ReactiveUI的异步API填充集合的最佳方法是什么?

C# 使用带有ReactiveUI的异步API填充集合的最佳方法是什么?,c#,asynchronous,system.reactive,reactiveui,C#,Asynchronous,System.reactive,Reactiveui,假设我有这个反应式UI视图模型结构,model是任意的模型类型 class ViewModel : ReactiveObject { private readonly ReactiveList<Model> _models; public IReactiveList<Model> Models { get { return _models; } } public IReactiveCommand LoadModels { get; private

假设我有这个反应式UI视图模型结构,
model
是任意的模型类型

class ViewModel : ReactiveObject
{
    private readonly ReactiveList<Model> _models;
    public IReactiveList<Model> Models { get { return _models; } }

    public IReactiveCommand LoadModels { get; private set; }
    public bool LoadingModels { get; private set; } // Notifies;
}
虽然我认为这两种方法都能奏效,但我有以下疑虑:

  • 在第一个示例中,我应该处理内部订阅,还是在内部可观察对象完成或出错时处理
  • 在第二个示例中,我知道
    GetModelsAsync
    方法中引发的异常将被忽略
从异步枚举(或者
IObservable
或者
Task
(或者
IObservable
更好)填充
ReactiveList
的“最佳”和最惯用的方法是什么

在了解了Octokit.net的反应式库是如何编写的之后,我编写了以下类以使API适应反应式世界:

class ObservableApi
{
    private readonly ITaskApi _taskApi;

    public IObservable<Model> GetModels() {
        return _taskApi.GetModelsAsync().ToObservable().SelectMany(c => c);
    }
}
虽然有时需要这样做(即展平集合),但通常更方便的做法是将其保留为
IEnumerable
,除非您计划对列表中的每个项调用异步方法。因为我们只想把所有的东西都放在一个列表中,所以我们不想这样做。只需将其保留为
Task

在第一个示例中,我应该处理内部订阅,还是在内部可观察对象完成或出错时处理

每当您在另一个Subscribe中有一个Subscribe时,您可能需要
SelectMany
操作符。然而,有一个更好的方法来做你想做的事情,你应该查看更多信息

下面是我编写代码的方法:

// In both cases, we want the command to be disabled when loading:
LoadModels = new ReactiveCommand();

LoadModels.RegisterAsyncTask(_ => taskClient.GetModelsAsync())
    .Subscribe(items => 
    {
        // This Using makes it so the UI only looks at the collection
        // once we're totally done updating it, since we're basically
        // changing it completely.
        using (_models.SuppressChangeNotifications())
        {
            _models.Clear();
            _models.AddRange(items);
        }
    });

LoadModels.ThrownExceptions
    .Subscribe(ex => Console.WriteLine("GetModelsAsync blew up: " + ex.ToString());

// NB: _loadingModels is an ObservableAsPropertyHelper<bool>
LoadModels.IsExecuting
    .ToProperty(this, x => x.LoadingModels, out _loadingModels);
//在这两种情况下,我们都希望在加载时禁用该命令:
LoadModels=new ReactiveCommand();
LoadModels.RegisterAsyncTask(=>taskClient.GetModelsAsync())
.订阅(项目=>
{
//这种使用使得UI只查看集合
//一旦我们完全完成了更新,因为我们基本上
//完全改变它。
使用(_models.SuppressChangeNotifications())
{
_模型。清除();
_型号。添加范围(项目);
}
});
LoadModels.ThrownException
.Subscribe(ex=>Console.WriteLine(“GetModelsAsync爆炸:”+ex.ToString());
//注意:_loadingModels是一个可观察的属性帮助器
LoadModels.i执行
.ToProperty(这个,x=>x.LoadingModels,out\u LoadingModels);

太棒了。如果我说我不希望你回答,那我就是在撒谎。谢谢。哦,我已经用了不到一个星期的ReactiveUI了,这太棒了。太棒了!如果你有任何问题,请ping StackOverflow,或者如果你不能概括/不想分享,请发邮件paul@paulbetts.orgI已将修改应用为o但是,我有一个问题,那就是
this.wheny(x=>LoadingModels,x=>!x.Value)
调用使事情在
\u loadingModels
null
时爆发,这自然是因为只有在
LoadModels
初始化后才将其设置为实际值。您是否建议先分配
\u loadingModels=observeableaspropertyHelper.Default(false)来解决此问题
或通过使用
new ReactiveCommand()
中的
allowscocurrentExecution
参数,或者我可以使用
new ReactiveCommand()
constructor,它已经将
allowscocurrentExecution
设置为
false
^;哦,是的,您根本不需要对when执行该操作。只需删除该行。我将修复代码示例
// In both cases, we want the command to be disabled when loading:
LoadModels = new ReactiveCommand(this.WhenAny(x => x.LoadingModels, x => !x.Value));

// First method, with the Observable API;
LoadModels.Subscribe(_ =>
    {
        LoadingModels = true;
        _models.Clear();
        observableClient.GetModels().ObserveOnDispatcher()
            .Subscribe(
                m => _models.Add(m),
                onCompleted: () => { LoadingModels = false; });
    });

// Second method, with the task API;
LoadModels.Subscribe(async _ =>
    {
        LoadingModels = true;
        try {
            var loadedModels = await taskClient.GetModelsAsync();
            _models.Clear();
            _models.AddRange(loadedModels);
        } catch (Exception ex) {
            RxApp.DefaultExceptionHandler.OnNext(ex);
        } finally {
            LoadingModels = false;
        }
    });
// In both cases, we want the command to be disabled when loading:
LoadModels = new ReactiveCommand();

LoadModels.RegisterAsyncTask(_ => taskClient.GetModelsAsync())
    .Subscribe(items => 
    {
        // This Using makes it so the UI only looks at the collection
        // once we're totally done updating it, since we're basically
        // changing it completely.
        using (_models.SuppressChangeNotifications())
        {
            _models.Clear();
            _models.AddRange(items);
        }
    });

LoadModels.ThrownExceptions
    .Subscribe(ex => Console.WriteLine("GetModelsAsync blew up: " + ex.ToString());

// NB: _loadingModels is an ObservableAsPropertyHelper<bool>
LoadModels.IsExecuting
    .ToProperty(this, x => x.LoadingModels, out _loadingModels);