【问题标题】:DynamicData: Sorting of bound list reloads on every changeDynamicData:每次更改时重新加载绑定列表的排序
【发布时间】:2018-05-04 18:08:31
【问题描述】:

我正在使用出色的 dynamicdata 将我的数据层桥接到我的 UI(使用 RxUI)。动态数据部分归结为以下典型代码。有一个 ItemViewModels ("_sourceCache") 的 SourceCache,它绑定到 ItemViewModels ("Models") 的 ReactiveList,后者又(在视图中)被绑定为 ListView.ItemsSource:

var propertyChanges = _sourceCache.Connect().WhenPropertyChanged(p => p.LastChange)
            .Throttle(TimeSpan.FromMilliseconds(250))
            .Select(_ => Unit.Default);

        var comparer = SortExpressionComparer<ItemViewModel>.Ascending(l => l.LastChange);

        _sourceCache.Connect()
            .Sort(comparer, propertyChanges)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Bind(Models)
            .Subscribe();

(可以找到完整的工作示例here

运行示例时,每次排序被属性更改触发时,整个列表都会重新加载可见(观察 LastChange 属性)。如果选择 ListViewItem,通常选择会丢失,而且整个列表的可见重新加载会让人分心。

我现在的问题是:有什么方法可以在我的 DynamicData 链中进行排序而不会出现上述问题?

理想情况下,只有更改过的项目会改变它们在列表中的位置,其余项目会保持可见。

更新

感谢 Roland 的提示,但观察到的行为仍然是相同的,无论是否使用

Sort(comparer, propertyChanges)

AutoRefresh(m => m.LastChange)
.Sort(comparer)

整个列表 UI 看起来仍然像重新加载一样(所有项目都会在每次更改时消失并重新出现)。从我链接的 github 存储库中可以看出,我随机选择绑定的 ItemViewModel 之一并更改“LastChanged”属性。也许这是 UWP ListView 的一种行为?

更新 2

如果我只是 ReactiveList.Move 每 1 秒随机移动一个项目,则可以看到相同的行为,但整个列表看起来好像每次都重新加载。所以我是 UWP ListView 本身...

【问题讨论】:

    标签: c# uwp dynamic-data reactiveui


    【解决方案1】:

    您使用的排序重载将强制每次属性更改和/或添加或更新新项目时完全采用。该重载旨在在比较器更改时使用,而不是在项目更改时使用。

    解决方案是使用AutoRefresh,它指示 dd 在属性更改时重新评估单个项目。

    .AutoRefresh(p=&gt;p.LastChange).Sort(comparer)

    指定节流阀和调度程序存在重载。

    【讨论】:

      【解决方案2】:

      更新

      实现了一个新的 DynamicData 操作,将“移动”更改转换为“删除旧索引”和“添加新索引”,称为 TreatMovesAsRemoveAdd,使用如下:

      _sourceCache.Connect()
              .Sort(comparer, propertyChanges)
              .TreatMovesAsRemoveAdd()
              .ObserveOn(RxApp.MainThreadScheduler)
              .Bind(Models)
              .Subscribe();
      

      旧答案:

      似乎 ListView 无法(语义上)处理移动项目。只需添加+删除。于是我按照Roland的建议,修改了SortedReactiveListAdaptor(复制过来修改如下方法:

          private void DoUpdate(IChangeSet<TObject, TKey> changes)
          {
              foreach (var change in changes)
              {
                  switch (change.Reason)
                  {
                      case ChangeReason.Add:
                          _target.Insert(change.CurrentIndex, change.Current);
                          break;
                      case ChangeReason.Remove:
                          _target.RemoveAt(change.CurrentIndex);
                          break;
                      case ChangeReason.Moved:
                      // ************************************** change from original ************************************************
                      //_target.Move(change.PreviousIndex, change.CurrentIndex);
                      //break;
                      // ************************************** ******************** ************************************************
                      case ChangeReason.Update:
                      {
                          _target.RemoveAt(change.PreviousIndex);
                          _target.Insert(change.CurrentIndex, change.Current);
                      }
                      break;
                  }
              }
      
          }
      

      所以所有移动都将被视为更新(RemoteAt + Insert) 所述 SortedReactiveListAdaptor 的应用将是:

      .Bind(new MovesToUpdatesReactiveListAdaptor<IItemViewModel, string>(Items))
      

      而不是通常的

      .Bind(Items)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-12
        相关资源
        最近更新 更多