INotifyCollectionChanged and INotifyPropertyChanged

Posts   
 
    
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 25-Jun-2010 23:58:23   

With the increasing adoption momentum of WPF after the release of VS2010, I wanted to know if LLBL's entityCollections implement INotifyCollectionChanged and if LLBL's entities implement INotifyPropertyChanged. Seems that implementing these two interfaces is what guarantees the seamless databinding that updates the UI automatically.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 26-Jun-2010 11:10:02   

Not INotifyPropertyChange and INotifyCollectionChanged, they implement the Winforms interfaces instead (IBindingList, IListChanged and INotifyPropertyChanged.

The WPF specific interfaces aren't implemented as they are defined in a .net assembly which isn't part of .net 2.0.

You can work around this btw, and add the INotifyPropertyChange (so not with a 'd' wink ) to a partial class of CommonEntityBase and use the On... methods of the base class to provide your way of intercepting when what happens.

For the collection, you'd need a partial class of EntityCollection<T> to implement INotifyCollectionChanged, which you can implement using IListChanged with one exception: when an element is removed from the collection, IListChanged doesn't have the proper index (as the element is already gone) so you need to intercept the remove action on CollectionCore<T> to get the proper deleted element

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 26-Jun-2010 13:35:52   

Thanks Frans. I think the current interfaces implemented by EntityBase2 and EntitCollectionBase2 are enough for a winFroms-like experience of design time databinding.

The unique experience of WPF comes from the declarative nature of XAML and VS2008/2010 designer that allows a developer to experience first had in the designer how his binded controls will look when populated with data.

For example, suppose I am designing a WPF data screen that has some text boxes and a ListView. And suppose I have changed the ListView's DataTemplate so my items in listView would look in a certain way. In XAML, I can actually declare a DataContext of an EntityCollection that has 3 or 5 entities in the XAML markup. The VS designer will immediately (if sources implement the necessary interfaces) update my designer UI to show me how my binded and populated ListView would look without having to actually run the application. At run time, I just replace the dataContext with another EntityCollection that is populated based on the application's context.

This indeed would greatly boost the productivity of the UI developer and allow for a much friendlier design time experience.

For the VS designer/XAML editor to allow this kind of experience in WPF databinding, the two interfaces (not sure WITH or WITHOUT dflushed ) need to be implemented by the Object/Collection data sources.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 28-Jun-2010 10:49:00   

Ok, understood. The interfaces are: INotifyCollectionChanged and INotifyPropertyChanging

The INotifyCollectionChanged event requires a filled NotifyCollectionChangedArgs object, which has an Action (you can use the IListChanged event value for that), NewItems and OldItems.

The NewItemsIndex and OldItemsIndex can be retrieved from the IListChanged event args, the NewItems object and OldItems object value can be retrieved by overriding OnEntityAdded and OnEntityRemoved in the partial class of EntityCollection<T> you need to implemented with the INotifyCollectionChanged interface.

INotifyPropertyChanging is an interface which offers an event, PropertyChanging, similar to PropertyChanged. In a partial class of CommonEntityBase, override OnSetValue, and in there simply raise the event. That's all.

If you run into probs implementing this, please let us know.

To add this by ourselves, we have to branch the runtime into a platform specific version, something we don't want to do at this point.

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 29-Jun-2010 00:18:13   

Thank you Frans for the guidance. Allow me just to add one final thought. In WPF, the adoption of MVVM is becoming as standard as adopting the technology itself (I myself don't even know how to build WPF UI without thinking of the View and the ViewModel unless it was a 'Hello Wolrd' app !!).

Implementing MVVM under WPF totally relies on the two-way databinding infrastructure between the View and the ViewModel. This two-way databinding relies on the ViewModel exposing Commands, Entities with Notifiable Properties, and Observable Collections to the View. Having the ability to expose LLBL's entities and EntityCollection as Notifiable Entities and Observable Collection would just add more marketing strength to the product under the umbrella of "WPF MVVM ready".

I know that one (specially of your caliber) could argue the architecture, but I remeber how on _some_occasions you were driven to add features to LLBL (like using Sprocs for CRUD) that were market driven rather than anything else.

My suggestion would NOT be for you to fork the LLBL code but rather to add the support for these interfaces in the generated DAL code through "optional" code-gen tasks or templates that the developer can select when he/she F7's LLBL.

psandler
User
Posts: 540
Joined: 22-Feb-2005
# Posted on: 29-Jun-2010 16:53:36   

Been struggling with and thinking about this general topic for a while now, so I thought I would add some of these questions to this thread. I think omar's questions were directed toward the LLBLGen runtime, but my questions are more in general, regardless of runtime (feel free to move this to a new thread if I'm hijacking).

A design issue I have been struggling with lately involves the different needs for entities across the different layers of the application.

There was a thread on stackoverflow that I was involved in: http://stackoverflow.com/questions/2906940/wpf-mvvm-delegating-a-domain-model-collection-to-a-viewmodel

Omar's questions and the linked thread's questions are specific to UI (and WPF, actually). But the same principles could apply to other layers as well. For example, you may need JSON entities for a web-based UI, you may need DTOs for WCF services, you may need field and collection change notification for WPF (as noted by Omar and in the linked thread).

In the SO thread, someone suggested using a dynamic proxy to add functionality to a domain object at run time. I think this is an interesting approach, but I'm not sure how difficult it would be.

My other thought was whether it would be possible in 3.0 to generate several different versions of each entity, all with uniform fields/fieldnames, and write (or generate) code that maps the values and (in some cases) the full graph from one to the other? In this way you could have separate representations/projections of each entity and all the functionality needed for each layer, without "cluttering" the entities with every possible interface that needs to be supported for a specific layer/framework.

Thoughts?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 30-Jun-2010 10:08:52   

omar wrote:

Thank you Frans for the guidance. Allow me just to add one final thought. In WPF, the adoption of MVVM is becoming as standard as adopting the technology itself (I myself don't even know how to build WPF UI without thinking of the View and the ViewModel unless it was a 'Hello Wolrd' app !!).

Implementing MVVM under WPF totally relies on the two-way databinding infrastructure between the View and the ViewModel. This two-way databinding relies on the ViewModel exposing Commands, Entities with Notifiable Properties, and Observable Collections to the View. Having the ability to expose LLBL's entities and EntityCollection as Notifiable Entities and Observable Collection would just add more marketing strength to the product under the umbrella of "WPF MVVM ready".

More buzzword compliance wink

I know that one (specially of your caliber) could argue the architecture, but I remeber how on _some_occasions you were driven to add features to LLBL (like using Sprocs for CRUD) that were market driven rather than anything else.

My suggestion would NOT be for you to fork the LLBL code but rather to add the support for these interfaces in the generated DAL code through "optional" code-gen tasks or templates that the developer can select when he/she F7's LLBL.

In v3 we have the ability to add 'settings' which are then settable in the designer and which values are then usable in the templates. We've decided to add a setting for this (disabled by default) so this code is generated automatically if the setting is switched on.

We hope to deliver this in the coming month.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 30-Jun-2010 10:15:40   

psandler wrote:

Been struggling with and thinking about this general topic for a while now, so I thought I would add some of these questions to this thread. I think omar's questions were directed toward the LLBLGen runtime, but my questions are more in general, regardless of runtime (feel free to move this to a new thread if I'm hijacking).

A design issue I have been struggling with lately involves the different needs for entities across the different layers of the application.

There was a thread on stackoverflow that I was involved in: http://stackoverflow.com/questions/2906940/wpf-mvvm-delegating-a-domain-model-collection-to-a-viewmodel

Omar's questions and the linked thread's questions are specific to UI (and WPF, actually). But the same principles could apply to other layers as well. For example, you may need JSON entities for a web-based UI, you may need DTOs for WCF services, you may need field and collection change notification for WPF (as noted by Omar and in the linked thread).

In the SO thread, someone suggested using a dynamic proxy to add functionality to a domain object at run time. I think this is an interesting approach, but I'm not sure how difficult it would be.

My other thought was whether it would be possible in 3.0 to generate several different versions of each entity, all with uniform fields/fieldnames, and write (or generate) code that maps the values and (in some cases) the full graph from one to the other? In this way you could have separate representations/projections of each entity and all the functionality needed for each layer, without "cluttering" the entities with every possible interface that needs to be supported for a specific layer/framework.

Thoughts?

What you're looking for seems to be an object-object mapper? The 'data' inside an entity class instance is the real entity instance, so what you do is create new types of buckets (classes) in which you can store that entity instance, so you can manipulate it in different areas.

So fetching an entity instance through an o/r mapper and then migrate the entity instance to a different class instance for using it in another area of the application (e.g. though serialization to silverlight/whatever) and back is the process you describe I think. In general it's straight forward to create migration code to transform an entity instance from one bucket to another. The problem is mostly around hierarchies: customer.Orders, so you have to have a different Customer bucket with a different container with Order buckets (I call them buckets here so you don't get confused with entity instances) so a parallel hierarchy. This makes transformation of the entity instances inside these hierarchies from one to another a bit more complex.

Frans Bouma | Lead developer LLBLGen Pro
GizmoTN76
User
Posts: 36
Joined: 22-Oct-2007
# Posted on: 27-Aug-2010 00:22:31   

Otis wrote:

Ok, understood. The interfaces are: INotifyCollectionChanged and INotifyPropertyChanging

The INotifyCollectionChanged event requires a filled NotifyCollectionChangedArgs object, which has an Action (you can use the IListChanged event value for that), NewItems and OldItems.

The NewItemsIndex and OldItemsIndex can be retrieved from the IListChanged event args, the NewItems object and OldItems object value can be retrieved by overriding OnEntityAdded and OnEntityRemoved in the partial class of EntityCollection<T> you need to implemented with the INotifyCollectionChanged interface.

INotifyPropertyChanging is an interface which offers an event, PropertyChanging, similar to PropertyChanged. In a partial class of CommonEntityBase, override OnSetValue, and in there simply raise the event. That's all.

If you run into probs implementing this, please let us know.

To add this by ourselves, we have to branch the runtime into a platform specific version, something we don't want to do at this point.

Any chance there's a sample implementation of INotifyCollectionChanged? I've been making a stab at it in a partial of CommonEntityBase but I'm not sure if I'm hitting the correct overloads of the NotifyCollectionChangedEventArgs corresponding to the listchanged options. Thanks!

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 27-Aug-2010 10:29:00   

For INotifyCollectionChanged, you should have used a partial class of EntityCollection<T>.

GizmoTN76
User
Posts: 36
Joined: 22-Oct-2007
# Posted on: 27-Aug-2010 10:39:09   

Walaa wrote:

For INotifyCollectionChanged, you should have used a partial class of EntityCollection<T>.

Sorry, actually I did, got the 2 mixed up in the reply. (Not that clueless I swear simple_smile ) Does someone have an implementation of this partial that implements the INotifyCollectionChanged interface by any chance? I wasn't exactly sure of the moved vs replaced vs changed overloads etc.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 27-Aug-2010 11:03:57   

Haven't worked with WPF before, but I found this blog post, which might be of a good help. http://japikse.blogspot.com/2009/07/inotifycollectionchanged-observable.html

GizmoTN76
User
Posts: 36
Joined: 22-Oct-2007
# Posted on: 27-Aug-2010 17:14:21   

Well in the process of trying to find a good implementation of attaching INotifyCollectionChanged glued on top of an IBindingList I ran across this post from Rocky about why you shouldn't do it simple_smile .

http://forums.lhotka.net/forums/p/3506/17402.aspx

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 27-Aug-2010 17:29:51   

GizmoTN76 wrote:

Well in the process of trying to find a good implementation of attaching INotifyCollectionChanged glued on top of an IBindingList I ran across this post from Rocky about why you shouldn't do it simple_smile .

http://forums.lhotka.net/forums/p/3506/17402.aspx

haha simple_smile

Well, I can imagine you want it though. The main reason is OldItems. IBindingList can't tell you which elements were removed. IListChanged can't either. It can be efficient for the bound control to know that and act accordingly.

The problem for implementing the interface is a bit bigger, come to think of it: an entity collection is bound through the DefaultView object of the collection, as it implements IListSource. So EntityView2<T> has to implement INotifyCollectionChanged for the bound control. This is a bit problematic as the view is the 'collection' bound to the control, not the collection you bind. So removing elements from the view, but not from the collection, will still require the event being raised. This is a bit problematic, because the filter is simply applied to elements, and no previous 'state' is kept, so 'OldItems' isn't obtainable (as IBindingList, and ListChanged, don't require this as removed elements aren't propagated).

So reading Rocky's post about his experience, I can indeed see why you shouldn't implement it if IBindingList (which is the case) is already implemented. The only 'advantage' INotifyCollection ... can have is that removed items are known in the event args, ListChanged doesn't do that, but as Rocky explained, implementing it on a class with IBindingList is not going to work, so that makes life easier for you and also for us as we can skip implementing it simple_smile

Frans Bouma | Lead developer LLBLGen Pro