Skip to content

Instantly share code, notes, and snippets.

@RolandPheasant
Last active June 20, 2022 15:29
Show Gist options
  • Save RolandPheasant/3bba5e32f2eefb70c538ce4acabf17cb to your computer and use it in GitHub Desktop.
Save RolandPheasant/3bba5e32f2eefb70c538ce4acabf17cb to your computer and use it in GitHub Desktop.
Extension for a transform with an inline update
public static class DynamicDataEx
{
/// <summary>
/// Transforms the items, and when an update is received, allows the preservation of the previous view model
/// </summary>
/// <typeparam name="TObject">The type of the object.</typeparam>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <typeparam name="TDestination">The type of the destination.</typeparam>
/// <param name="source">The source.</param>
/// <param name="transformFactory">The transform factory.</param>
/// <param name="updateAction">Apply changes to the original. Example (previousTransformedItem, newOriginalItem) => previousTransformedItem.Value = newOriginalItem </param>
/// <returns></returns>
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) =>
{
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."));
updateAction(previous, change.Current);
//send a refresh as this will force downstream operators
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());
}
}
@RolandPheasant
Copy link
Author

That will be accommodated for when I port the operator into the library.

The existing transform operator by default also does not respond to a refresh but, has a "transformOnRefresh" flag which the user can opt into.

For now, you can simply add an extra line of code to the snippet.

 case ChangeReason.Update:
{

should become

 case ChangeReason.Refresh:
 case ChangeReason.Update:
{

and it will do as you expect

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment