-
Type: Improvement
-
Resolution: Unresolved
-
Priority: Minor - P4
-
None
-
Affects Version/s: None
-
Component/s: None
-
3 - M (<= 1 month)
-
1726
Feature request - I almost think it is a bug
Today (at least with Realm 3.0.0) PropertyChanged are not raised until the transaction is committed on the thread owning the transaction. In this all realms are treated equal including the realm that has the transaction.
For short lived transaction you will hardly notice, but for transaction that lives longer, fx. to support complex undo scenarios, this is a problem, since the UI will not automatically update while the transaction is ongoing :-/
I would suggest that while in a transaction, the PropertyChanged is raised immediately on the owning thread and re-raised, if the transaction is rolled back. All other threads should raise event when the transaction is committed.
I think this would be a better fit with the expectations of .NET programmers, and would make it trivial to use Realm to implement complex undo functionality, by taking advantage of long running transactions, combined with realms deterministic and automatic conflict resolution, that will ensure that conflicts are always resolved - which is where Realm really shines compared to the competitors.
I have have included a test-case to illustrate the "problem":
`
public class Dork : RealmObject { public int State { get; set; } public int ShadowState { get; set; } protected override void OnPropertyChanged(string propertyName) { switch (propertyName) { case nameof(State): if (!IsManaged || Realm.IsInTransaction) ShadowState = State; else Realm.Write(() => ShadowState = State); break; } } } public class RealmTests { [Test] public void PropertyChangedRaisedEvenIfNotManagedYetTest() { AsyncContext.Run(async () => { var config = new RealmConfiguration("test.db"); Realm.DeleteRealm(config); using (var realm = Realm.GetInstance(config)) { var d = new Dork { State = 1 }; Assert.That(1, Is.EqualTo(d.State)); Assert.That(d.State, Is.EqualTo(d.ShadowState)); d.State = 2; Assert.That(2, Is.EqualTo(d.State)); Assert.That(d.State, Is.EqualTo(d.ShadowState)); realm.Write(() => { realm.Add(d); d.State = 3; }); Assert.That(3, Is.EqualTo(d.State)); Assert.That(d.State, Is.Not.EqualTo(d.ShadowState)); // Sadly so :-/ d.PropertyChanged += (s, e) => { }; // just here to show interest using (var transaction = realm.BeginWrite()) { d.State = 4; await Task.Yield(); Assert.That(4, Is.EqualTo(d.State)); Assert.That(d.State, Is.Not.EqualTo(d.ShadowState)); // Sadly so :-/ transaction.Commit(); } await Task.Yield(); // otherwise OnPropertyChanged won't be raised! :-/ Assert.That(4, Is.EqualTo(d.State)); Assert.That(d.State, Is.EqualTo(d.ShadowState)); // now it works realm.Write(() => d.ShadowState = 0); // reset shadow state! using (var transaction = realm.BeginWrite()) { d.State = 5; transaction.Rollback(); } await Task.Yield(); Assert.That(4, Is.EqualTo(d.State)); Assert.That(0, Is.EqualTo(d.ShadowState)); // Sadly so :-/ } }); } }
The obvious next question becomes, what about RealmResult and RealmList? Well, I expect that doing this for RealmResult would be near impossible, but that it could be done for RealmList at least to the extend that a simple Refresh event is raised on roll-back.