TrackedBindingList ListChanged not firing for existing INotifyPropertyChanged

Thread is closed for posting
2 posts, 0 answers
  1. Galin
    Galin avatar
    7 posts
    Member since:
    Aug 2013

    Posted 18 Dec 2014 Link to this post

    I'm having an issue with the TrackedBindingList: in the constructor of my view model I subscribe to the ListChanged event of my model's collection, in order to update a VM property representing a summary of the collection- let's say TotalCost = order.Products.Sum(p=> p.Cost). Since Product implements INotifyPropertyChanged I expect to be notified both when the collection changes(add/remove) and Product.Cost changes as well, so that I can update the summary. Simple enough- however it only works for Products that are inserted after subscribing to the event- deleting an existing product does trigger the event, however modifying the cost of a product that was already present in the collection does not.

    Also as a bonus question I was wondering what would be the correct way for implementing a "reset" functionality? As soon as the OpenAccessContext is modified a 'Reset' button becomes visible- clicking it ClearsChanges, but how do I update the UI after? As a quick fix I made the topmost entity raise a OnPropertyChanged(string.Empty) but that only updates it's own fields- all navigational properties(my TrackedBindingLists) stay silent- so the item-cost from before is not reverted(on the UI).
  2. Boris Georgiev
    Boris Georgiev avatar
    190 posts

    Posted 23 Dec 2014 Link to this post

    Hi Galin,

    This is the expected behavior in this case. TrackedBindingList will trigger the event only when a new object is added to the collection or an existing one is removed. The event will not be triggered if you only change one property of an object which is already in the collection. To workaround this, you could create your own event which is triggered when a specific property is changed or you could include your logic in the PropertyChangedEventHandler and handle the changes for the specific properties.

    If you want to reload an object and the entities in its references collection the best practice is to create a new context and load the object from there. If you want to load it from the same context, you could use the context.Refresh() method, after the method is called it will update an object in the context with the data from the database. Then next time when you access the navigation collection property, it will execute a new query to get the objects in the navigation collection property from the database.

    There are two cases where it will not execute query to load the data from the database: if you stored the collection in a variable and you work directly with the variable or if the navigation property is a reference(not collection) it will not load the object again.

    Examples with SofiaCarRental database:
    In this case, a new query to load the new data will be executed: 
    var car = context.Cars.FirstOrDefault();
    var ro = car.RentalOrders;
    context.Refresh(Telerik.OpenAccess.RefreshMode.OverwriteChangesFromStore, car);
    var ro2 = car.RentalOrders;

    In this cases, new queries will not be executed to load the new data: 
    var car = context.Cars.FirstOrDefault();
    var category = car.Category;
    context.Refresh(Telerik.OpenAccess.RefreshMode.OverwriteChangesFromStore, car);
    var category2 = car.Category;
    var category2 = car.Category;
    var car = context.Cars.FirstOrDefault();
    var ro = car.RentalOrders;
    context.Refresh(Telerik.OpenAccess.RefreshMode.OverwriteChangesFromStore, car);
    var firstRentalOrder = ro.FirstOrDefault();

    I hope that helps. If any other questions arise, do not hesitate to contact us again.

    Boris Georgiev
    OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
Back to Top