Создайте полученную коллекцию ViewModels с DynamicData, которая обновляет существующий элемент вместо создания нового при изменении исходного элемента - PullRequest
0 голосов
/ 19 декабря 2018

Например, у меня есть заметка о некоторых коллекциях, которая указывает статусы объектов (я получаю их периодически через REST API).

class User
{
    int Id { get; }
    string Name { get; }
    string Status { get; }
}

IObservable<User> source;

Я хочу создать DynamicCache объект и обновлять его каждыйвремя source дает мне новый результат.Поэтому я написал:

var models = new SourceCache<User,int>(user => user.Id);
models.Connect()
      .Transform(u => new UserViewModel() {...})
      ...
      .Bind(out viewModels)
      .Subscribe();

source.Subscribe(ul => models.EditDiff(ul, (a, b) => a.Status == b.Status));

Но теперь каждый раз, когда пользователь меняет свой статус, метод .Transform(...) создает новый экземпляр UserViewModel, что не является желаемым поведением.

Могу ли я как-то определить правило обновления существующих свойств ViewModel (в производной коллекции), когда исходный элемент с тем же Id меняется, вместо того, чтобы каждый раз создавать новый?

1 Ответ

0 голосов
/ 20 декабря 2018

Ответ: вам нужно создать пользовательский оператор.Я разместил здесь суть TransformWithInlineUpdate , которую вы можете скопировать в свое решение.Пример использования:

var users = new SourceCache<User, int>(user => user.Id);

var transformed =  users.Connect()
    .TransformWithInlineUpdate(u => new UserViewModel(u), (previousViewModel, updatedUser) =>
        {
            previousViewModel.User = updatedUser;
        });

Для полноты ответа, вот код:

    public static IObservable<IChangeSet<TDestination, TKey>> TransformWithInlineUpdate<TObject, TKey, TDestination>(this IObservable<IChangeSet<TObject, TKey>> source,
        Func<TObject, TDestination> transformFactory,
        Action<TDestination, TObject> updateAction = null)
    {
        return source.Scan((ChangeAwareCache<TDestination, TKey>)null, (cache, changes) =>
            {
                //The change aware cache captures a history of all changes so downstream operators can replay the changes
                if (cache == null)
                    cache = new ChangeAwareCache<TDestination, TKey>(changes.Count);

                foreach (var change in changes)
                {
                    switch (change.Reason)
                    {
                        case ChangeReason.Add:
                            cache.AddOrUpdate(transformFactory(change.Current), change.Key);
                            break;
                        case ChangeReason.Update:
                        {
                            if (updateAction == null) continue;

                            var previous = cache.Lookup(change.Key)
                                .ValueOrThrow(()=> new MissingKeyException($"{change.Key} is not found."));
                            //callback when an update has been received
                            updateAction(previous, change.Current);

                            //send a refresh as this will force downstream operators to filter, sort, group etc
                            cache.Refresh(change.Key);
                        }
                            break;
                        case ChangeReason.Remove:
                            cache.Remove(change.Key);
                            break;
                        case ChangeReason.Refresh:
                            cache.Refresh(change.Key);
                            break;
                        case ChangeReason.Moved:
                            //Do nothing !
                            break;
                    }
                }
                return cache;

            }).Select(cache => cache.CaptureChanges()); //invoke capture changes to return the changeset
    }
...