我应该如何使用Rx + DynamicData定期检查许多在线服务的更新?

时间:2018-12-02 23:40:22

标签: uwp reactiveui reactivex asp.net-dynamic-data

我有一个基本的Calendar / Agenda应用程序,它将列出一系列帐户和日历中的最新事件。例如,假设我有3个帐户:两个不同的Microsoft帐户和一个Google帐户。我目前将它们存储为服务(SourceCache<Account, string>)中称为Accounts的{​​{1}}。

AccountsService是DynamicData的一部分,它基本上是Reactive Collections的一部分。我希望它具有反应性,以便在我添加或删除帐户时,应用程序中的所有内容(设置页面,日历页面等)都将自动更新。

现在,每个帐户可以有多个SourceCache<T1,T2>。对于每个Calendar,我想下载所有即将推出的Calendar。问题是我需要定期执行此操作,以查看是否已添加新事件或事件是否已更改。

这是我当前的操作方式,但恐怕Rx可能真的很糟糕。

CalendarEvent

最重要的是,事件也通过订阅可观察对象来加载。那是我放置计时器的地方,它使我可以控制检查在线服务的频率。看起来像这样(20秒仅用于测试!):

var calendarSet = this.accountsService.Accounts.Connect()
    .ObserveOn(RxApp.TaskpoolScheduler)
    .TransformMany(x =>
    {
        ReadOnlyObservableCollection<Models.Calendar> subCalendars;
        x.CalendarService.Calendars.Connect()
            .AutoRefreshOnObservable(calendar => calendar.IsEnabledChanged)
            .AutoRefreshOnObservable(calendar => calendar.IsColorChanged)
            .Filter(calendar=>calendar.IsEnabled)
            .Bind(out subCalendars)
            .Subscribe();
        return subCalendars;
     }, x => x.CacheKey)
     .ObserveOnDispatcher()
     .Publish();

calendarSet
    .Bind(out calendars)
    .Subscribe();


var eventSet = calendarSet
    .ObserveOn(RxApp.TaskpoolScheduler)
    .Transform( calendar =>
    {
        var events = new List<Models.CalendarEvent>();
        Debug.WriteLine(calendar.Name);
        calendar.CalendarService.CalendarEventsObservable(calendar).Subscribe(items =>
        {
            events.AddRange(items);
        });
        return events;
    })
    .TransformMany(x => x, x => x.Key)
    .Filter(x => x.EndDateTime > DateTimeOffset.Now)
    .Sort(new Models.CalendarEventSorter())
    .ObserveOnDispatcher()
    .Bind(out calendarEvents)
    .Subscribe();

calendarSet.Connect();

这似乎有效!我可以启用/禁用某些日历,事件将在绑定列表中显示或消失。我可以看到事件每隔一定的时间就会更新……并且我假设由于我使用的TransformMany的密钥与public IObservable<List<Models.CalendarEvent>> CalendarEventsObservable(Models.Calendar calendar) { var obs = Observable.Interval(TimeSpan.FromSeconds(20)).SelectMany(async x => { var items = await GetAllEventsForCalendarAsync(calendar); return items; }); return obs; } 的在线ID(已固定)相关联,因此新下载的事件仅替换了缓存中的旧文件。我在用户界面上看不到任何闪烁。

**更正:似乎是因为我不小心从另一个试验中遗留下来的骇客而起作用。在原始帐户SourceCache上,我正在运行一个调用Accounts.Refresh()的计时器。如果我将其取出,将无济于事。

这是正确的方法吗?拜托,请赐教...我在Rx和DynamicData方面有点挣扎。有很多操作员,我还不知道该怎么办。

谢谢!

2 个答案:

答案 0 :(得分:2)

您似乎已经回答了自己的问题,并且代码看起来比原始代码更优化。但是我建议可以进行优化:

  1. 使用AutoRefreshOnObservable,这将使您可以创建单个可观察对象,而不是两次使用AutoRefresh。

  2. 我无法从代码中判断CalendarEventsObservable是返回单个值还是集合。如果它返回一个集合,则可以使用EditDiff代替使用AddOrUpdate。 EditDiff期望比较指定的相等性,并防止触发不必要的通知。

答案 1 :(得分:0)

我已经重写了一些代码,它似乎工作得更好。即使没有黑客,我也可以在原始Refresh() Account上手动调用SourceCache

我意识到我一直在滥用Publish方法。另外,在transform语句中订阅可观察对象将不会起作用,因为它不是DynamicData可观察对象(具有变更集)。相反,我决定做一个SubscribeMany来订阅来自每个CalendarEventObservable的所有Calendar,在订阅的Action逻辑中,我将填充SourceCache中的新CalendarEvent s。没有事件会被删除,但是由于缓存键的存在,重复的事件只会覆盖旧的事件,而且我可以从未选择的日历中过滤掉事件。

 private SourceCache<Models.CalendarEvent, string> calendarEventCache;
 public IObservableCache<Models.CalendarEvent, string> CalendarEventCache => calendarEventCache.Connect().AutoRefreshOnObservable(x=>x.Parent.IsEnabledChanged).Filter(x=>x.Parent.IsEnabled).AsObservableCache();

//////////////////
///IN CONSTRUCTOR:

        calendarEventCache = new SourceCache<Models.CalendarEvent, string>(x => x.Key);

        calendarsCache = this.accountsService.Accounts.Connect()
            .ObserveOn(RxApp.TaskpoolScheduler)
            .TransformMany(x =>
            {
                ReadOnlyObservableCollection<Models.Calendar> subCalendars;
                x.CalendarService.Calendars.Connect()
                            .AutoRefreshOnObservable(calendar => calendar.IsEnabledChanged)
                            .AutoRefreshOnObservable(calendar => calendar.IsColorChanged)
                            .Filter(calendar => calendar.IsEnabled)
                            .Bind(out subCalendars)
                            .Subscribe();
                return subCalendars;
            }, x => x.CacheKey)
            .ObserveOnDispatcher()
            .AsObservableCache();

        calendarsCache.Connect()
            .ObserveOn(RxApp.TaskpoolScheduler)
            .SubscribeMany(calendar =>
            {
                return calendar.CalendarService.CalendarEventsObservable(calendar).Subscribe(calendarEvent =>
               {
                   calendarEventCache.AddOrUpdate(calendarEvent);
               });
            })
            .Subscribe();

现在,在UI的视图模型中,我订阅了SourceCache<CalendarEvent,string>