検索フリップなどのタイムラインの基幹部分
Inheritance: IDisposable
 public TimelineViewModelBase(TimelineModelBase model)
 {
     this._model = model;
     this._timeline = new ObservableCollection<StatusViewModel>();
     DispatcherHolder.Enqueue(this.InitializeCollection, DispatcherPriority.Background);
     this.CompositeDisposable.Add(
         new EventListener<Action<bool>>(
             h => model.InvalidationStateChanged += h,
             h => model.InvalidationStateChanged -= h,
             s => this.IsLoading = s));
     this.CompositeDisposable.Add(() =>
     {
         if (_listener != null) _listener.Dispose();
     });
     this.CompositeDisposable.Add(
         this.ListenPropertyChanged(() => this.CurrentAccounts)
             .ObserveOnDispatcher()
             .Select(_ => this.CurrentAccounts.ToArray())
             .Subscribe(a => _timeline.ForEach(s => s.BindingAccounts = a)));
     this.IsLoading = true;
     this._model.InvalidateTimeline();
 }
 public TimelineViewModelBase(TimelineModelBase model)
 {
     this._model = model;
     this._timeline = new ObservableCollection<StatusViewModel>();
     DispatcherHelper.UIDispatcher.InvokeAsync(this.InitializeCollection, DispatcherPriority.Background);
     this.CompositeDisposable.Add(
         new EventListener<Action<bool>>(
             h => model.IsLoadingChanged += h,
             h => model.IsLoadingChanged -= h,
             isLoading =>
             {
                 if (isLoading)
                 {
                     // send immediate
                     // ! MUST BE DispatcherPriority.Send ! 
                     // for update binding value before beginning rendering.
                     DispatcherHelper.UIDispatcher.InvokeAsync(() =>
                     {
                         this.IsLoading = true;
                     }, DispatcherPriority.Send);
                 }
                 else
                 {
                     // wait for dispatcher
                     DispatcherHelper.UIDispatcher.InvokeAsync(() =>
                     {
                         // this clause is invoked later, so re-check currrent value
                         if (model.IsLoading == false)
                         {
                             this.IsLoading = false;
                         }
                     }, DispatcherPriority.ContextIdle);
                 }
             }));
     this.CompositeDisposable.Add(() =>
     {
         if (_listener != null) _listener.Dispose();
     });
     this.CompositeDisposable.Add(
         this.ListenPropertyChanged(() => this.CurrentAccounts,
             e => DispatcherHelper.UIDispatcher.InvokeAsync(() =>
             {
                 var a = this.CurrentAccounts.ToArray();
                 this._timeline.ForEach(s => s.BindingAccounts = a);
             })));
     this.CompositeDisposable.Add(
         Setting.ScrollLockStrategy.ListenValueChanged(
             v =>
             {
                 RaisePropertyChanged(() => this.IsScrollLockEnabled);
                 RaisePropertyChanged(() => this.IsScrollLockOnlyScrolled);
             }));
     this.CompositeDisposable.Add(
         Setting.IsAnimateScrollToNewTweet.ListenValueChanged(
             v => RaisePropertyChanged(() => IsAnimationEnabled)));
     this.CompositeDisposable.Add(
         Setting.IsScrollByPixel.ListenValueChanged(
             v =>
             {
                 RaisePropertyChanged(() => ScrollUnit);
                 RaisePropertyChanged(() => IsAnimationEnabled);
             }));
     this._model.InvalidateTimeline();
 }