Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: ResetOnFirstTimeLoad not working with sorting #929

Open
DevEngineReq opened this issue Aug 22, 2024 · 11 comments · Fixed by #935 · May be fixed by #939
Open

[Bug]: ResetOnFirstTimeLoad not working with sorting #929

DevEngineReq opened this issue Aug 22, 2024 · 11 comments · Fixed by #935 · May be fixed by #939
Labels

Comments

@DevEngineReq
Copy link

DevEngineReq commented Aug 22, 2024

Describe the bug 🐞

If we use a sorting (e.g. Sort()) resetOnFirstTimeLoad is not working / has no affect.
image
(For SortAndBind i did not find resetOnFirstTimeLoad)

Without sorting it works as expected.
image

May be this is the problem

Adapt Method with ChangeSet (resetOnFirstTimeLoad is OR related) WORKS
AdaptChangeSet

Adapt Method with SortedChangeSet (resetOnFirstTimeLoad is && related) NOT WORKING
AdaptSortedChangeSet

With version 8.0.2 it work as expected. If I reconnect to cache a reset was triggered on first time load;
With version 8.1.1 and newer a reset was only triggered if change count > threshold

Step to reproduce

See Description

Reproduction repository

https://github.com/reactivemarbles/DynamicData

Expected behavior

Reset on first time load while using sorting

Screenshots 🖼️

No response

IDE

Visual Studio

Operating system

Windows

Version

No response

Device

No response

DynamicData Version

9.0.4

Additional information ℹ️

No response

@JakenVeina
Copy link
Collaborator

I'll defer to @RolandPheasant for the design intent behind these operators, but I can confirm the behavior you describe, the logic of the change seems sound, and implementing the change doesn't break any existing testing.

@RolandPheasant
Copy link
Collaborator

Ok. This is clearly a bug and needs fixing.

However, for the latest version 9, sort has been marked obsolete and it's been replaced by SortAndBind. Therefore upgrading may be a bit painful just to see whether the new version works. Instead I'll take a look early next week and see whether I can provide a snippet for a new adaptor which you could add into your codebase.

@DevEngineReq
Copy link
Author

Currenty we are using the Version 9.0.4. Due to that we switched from .Sort() + .Bind() to .SortAndBind()
As default we use a ReadOnlyObservableCollection together with .SortAndBind(out ,....)
In this cases the SortAndBind works because the list is already empty.

But in one case we need to use a ObservableCollectionExtended (which already contains objects) + change Binding at runtime
And for this case ResetOnFirstTimeLoad is requried.
Is there ia trick how SortAndBind does support ResetOnFirstTimeLoad. In our case it does not work.
SortAndBindOptions has no const DefaultResetOnFirstTimeLoad like BindingOptions

@JakenVeina
Copy link
Collaborator

JakenVeina commented Aug 31, 2024

But in one case we need to use a ObservableCollectionExtended (which already contains objects) + change Binding at runtime

What does this look like, in a query?

@DevEngineReq
Copy link
Author

I created a repository with a small example project which shows the problem.
Repository

@JakenVeina
Copy link
Collaborator

JakenVeina commented Sep 3, 2024

To me, I'm not convinced this (clearing the binding target, during subscription) is a behavior that either .Bind() or .SortAndBind() are really responsible for. I'm also not convinced this shouldn't just be what the operators ALWAYS do. We'll have to talk about this one, a bit.

In the meantime, if you haven't already, this is quite easily worked-around.

If you're going to be manually switching bindings, I'd say it becomes your responsibility to just .Clear() the collection before you apply the new binding.

private void Connect()
{
    this.LastConnect = DateTime.UtcNow;
    this.cacheDisposable?.Dispose();

    this.users.Clear();

    this.cacheDisposable = this.userCache.Connect()
        .ObserveOn(RxApp.TaskpoolScheduler)
        .Filter(static x => x.Id < 10) //lower than Binding ResetThreshold to avoid reset due to too many changes
        .ObserveOn(RxApp.MainThreadScheduler)
        .SortAndBind(this.users, this.sorter)
        .Subscribe();
}

Or you can let RX and DynamicData do the binding-management for you, where the .Clear() is already baked in.

this.cacheDisposable = Observable.Interval(TimeSpan.FromSeconds(3))
    .StartWith(0)
    .ObserveOn(RxApp.MainThreadScheduler)
    .Do(_ => this.LastConnect = DateTime.UtcNow)
    .ObserveOn(RxApp.TaskpoolScheduler)
    .Select(_ => this.userCache.Connect()
        .Filter(static x => x.Id < 10))
    .Switch()
    .ObserveOn(RxApp.MainThreadScheduler)
    .SortAndBind(this.users, this.sorter)
    .Subscribe();

ResetOnFirstTimeLoad maybe still makes sense as an adapter-level behavior, I.E. it's a potential optimization for certain implementations of ObservableCollection

@DevEngineReq
Copy link
Author

DevEngineReq commented Sep 3, 2024

Thank you for the bugfix #926. This will help us to use the newest DynamicData Version, because the Sort() is still available and the .Bind() supports ResetOnFirstTimeLoad. Is there a release date?

We need ResetOnFirstTimeLoad not only for avoid ambiguous objects (like in my example app)
but also for our WPF Persist Selection Behavior which needs NotifyCollectionChangedAction.Reset to handle the selection in the datagrid.

A normal .clear() will remove the selection. Of course we can cache the selection and set back within the viewmodel, but at this time we do not know if the object still available in the list. (other cache, filter sorting… very dynamic)

Is there a way to bring back the ResetOnFirstTimeLoad option in SortAndBind?
Or can I do it myself and yes what would that look like, so i can use SortAndBind in the futher.

@JakenVeina
Copy link
Collaborator

We need ResetOnFirstTimeLoad [...] for our WPF Persist Selection Behavior which needs NotifyCollectionChangedAction.Reset to handle the selection in the datagrid.

That definitely sounds like you should be using .Switch() then. If that operator isn't triggering a Reset when switching subscriptions, I would say that's a bug we can attempt to fix.

I'm also curious how a Reset preserves the selection. A DataGrid normally preserves selections by equality-comparison, right? Do you have a custom .Equals() implementation on these objects? Or are somehow otherwise overriding equality comparison?

@JakenVeina JakenVeina reopened this Sep 4, 2024
@RolandPheasant
Copy link
Collaborator

RolandPheasant commented Sep 4, 2024

I am working to make ResetOnFirstTimeLoad and opt-in option for SortAndBind.

A system wide opt-in for this old behaviour will be achieved as follows:

DynamicDataOptions.SortAndBind = DynamicDataOptions.SortAndBind with { ResetOnFirstTimeLoad = true };

Adding this option will not lead to too much code complexity, but will help consumers maintain old behaviours. I am also thinking about adding a Scheduler options for the bindings. Then ObserveOn(MainThreadScheduler) will be redundant.

@RolandPheasant RolandPheasant linked a pull request Sep 4, 2024 that will close this issue
@DevEngineReq
Copy link
Author

That would be great. Thank you.

@JakenVeina
Copy link
Collaborator

@RolandPheasant

I am also thinking about adding a Scheduler options for the bindings

There's another issue related to this, actually, if you hadn't spotted it. #932.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
3 participants