Any reason why IEditableCollectionView isn't implimented?

Any reason why IEditableCollectionView isn't implimented?

Old forum URL: forums.lhotka.net/forums/t/9969.aspx


rfcdejong posted on Friday, January 21, 2011

The infragistics datagrid worked in 3.8 using the BLB and all the time i wanted the BLB to derive from ObservableCollection. I'm happy that 4.0 that has been done by default and for legacy the BBLB is available.

It seems that the BLB is not implimenting the IEditableCollectionView so that binding must be done against a CollectionViewSource.GetDefaultView() resulting into using a ListCollectionView.

At the moment our framework causes directly binding against an abstractionlayer of a BO containing BLB properties etc. Not using a datasource or view objects.

Is there a reason why the IEditableCollectionView interface isn't implimented?

RockfordLhotka replied on Monday, January 24, 2011

I looked at this interface, and I'm pretty sure I've said this in a previous thread.

It is a view interface, not a model interface. Years ago I made the mistake of putting view-level concerns too deeply into the collection base class, and that was a bad mistake - one I had to fix in CSLA 2.0 with SortedBindingList, etc.

iirc, IEditableCollectionView supports things like paging, which can't be supported at the BLB level.

JonnyBee replied on Tuesday, January 25, 2011

No. It has nothing to do with paging. http://msdn.microsoft.com/en-us/library/system.componentmodel.ieditablecollectionview.aspx

"Defines methods and properties that a CollectionView implements to provide editing capabilities to a collection."

Properties:
CanAddNew
CanCancelEdit
CanRemove
CurrentAddItem
CurrentEditItem
IsAddingNew
IsEditingItem
NewItemPlaceholderPosition

Methods:

AddNew
CancelEdit
CancelNew
CommitEdit
CommitNew
EditItem
Remove
RemoveAt

RockfordLhotka replied on Tuesday, January 25, 2011

Ahh, so a different interface.

I still wonder if it should be implemented directly in the model. It is clearly a "view" interface, and past experience implementing "view" oriented interfaces in the model (CSLA) has not proven to be a good choice.

Microsoft clearly expects that we'll be using CVS objects in the view to mediate interaction with the model, and I surely don't want to fight with Microsoft. I tried that with Windows Forms for years and ultimately it caused nothing but pain...

JonnyBee replied on Tuesday, January 25, 2011

I'm wondering if this could be implemented in a wrapper class -  much like SortedBindingList and FilteredBindingList.

I believe it could be "cluttering up the code" to implement this directly in the model.

If anyone is up for a try on this you may publish the code at CslaContrib!!

 

RockfordLhotka replied on Tuesday, January 25, 2011

It is implemented in a wrapper class called CollectionViewSource :)

JonnyBee replied on Tuesday, January 25, 2011

No, CollectionViewSource does NOT implement IEditableCollectionView

Public Class CollectionViewSource
Inherits DependencyObject
Implements ISupportInitialize, IWeakEventListener

RockfordLhotka replied on Tuesday, January 25, 2011

So now I'm puzzled as to the purpose of this interface?

Normally the datagrid controls appear to work just fine through a CVS to a BLB (ObservableCollection) right?

rfcdejong replied on Wednesday, April 06, 2011

Sorry for answering 3 months later..

But i had other work @ work then upgrading to CSLA 4.x
I'm back into this issue  

It's not the datagrid i'm talking about, it's the Infragistics grid.
Infragistics "AddNew" functionality expect a IBindingList or a Viewer
http://blogs.infragistics.com/forums/p/41946/232427.aspx

In csla.xaml i would expect the "ViewModel" to impliment this, at least..

I'm going to build it into our own framework

PS: I don't know why i mentioned the interface in my first post..

RockfordLhotka replied on Wednesday, April 06, 2011

Thank you for getting back with your thoughts.

This is in line with my thinking too - that the interface is a view or viewmodel concern, not something that BLB should implement (for example).

It is possible that a future Csla.Xaml will have more detailed viewmodel types - such as one for a single object vs one for an editable collection.

I suspect that'll be more of a 4.3 thing, because 4.2 is almost entirely focused on mono/monotouch/monodroid support.

I expect 4.3 to be all about Silverlight 5, and therefore XAML-related functionality.

rfcdejong replied on Thursday, April 07, 2011

No problem, there is just alot of work to do.. 
I was almost about to derive from the old version of BLB, the BBLB

After switching to the latest infragistics controls (.NET 4.0 WPF 2010 volume 3) i still didn't manage to get it working.

There is an issue in .NET with empty collections and somehow the CanAddNew is always false when the constructor is internal.
I tried to use reflection to tell the collection the constructor to use but still it didn't work.

Finally i got it working by just making the constructor public.. and ofcourse wrap the BusinessList in a CollectionView (by using GetDefaultView())

Here is my code, a bit hacky assuming a IEditableCollection is always a BusinessListBase<,>

#if !SILVERLIGHT                
                if (model is IObservableBindingList && model is IEditableCollection)
                {
                    _collectionView = CollectionViewSource.GetDefaultView(model);
 
                    var args = model.GetType().BaseType.GetGenericArguments();
                    var type = args[1];
 
                    ConstructorInfo ci = type.GetConstructor(
                            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                            nullType.EmptyTypes, null);
 
                    FieldInfo field = _collectionView.GetType().GetField("_itemConstructor"BindingFlags.Instance | BindingFlags.NonPublic);
                    field.SetValue(_collectionView, ci);
                    return _collectionView;
                }
#endif

rfcdejong replied on Thursday, April 07, 2011

Ok "The final solution", without the need to make the constructors public.. after looking at the .NET source code for the ListCollectionView.cs
Again using reflection... there is another private boolean in the .NET code screwing around.. just need to set it true so it doesn't mess all up.

#if !SILVERLIGHT                
                if (model is IObservableBindingList && model is IEditableCollection)
                {
                    _collectionView = CollectionViewSource.GetDefaultView(model);
                    if (_collectionView is ListCollectionView)
                    {
                        var args = model.GetType().BaseType.GetGenericArguments();
                        var type = args[1];
 
                        ConstructorInfo ci = type.GetConstructor(
                                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                                nullType.EmptyTypes, null);
 
                        var itemConstructor = _collectionView.GetType().GetField("_itemConstructor"BindingFlags.Instance | BindingFlags.NonPublic);
                        itemConstructor.SetValue(_collectionView, ci);
 
                        var isItemConstructorValid = _collectionView.GetType().GetField("_isItemConstructorValid"BindingFlags.Instance | BindingFlags.NonPublic);
                        isItemConstructorValid.SetValue(_collectionView, true);
 
                        return _collectionView;
                    }
                }
#endif

rfcdejong replied on Monday, April 18, 2011

Because i totally forgot about the AddNewCore calling the static factory methods to create an item, the post above are bugged.
And Microsoft didn't expose any virtual methods in the ListCollectionView so i don't see a very elegant way to override methods.

Reintroducing them and re-implimenting the interfaces is the work around i implimented in our frontend framework.

if (model is IObservableBindingList && model is IEditableCollection)
{
    _collectionView = new MyListCollectionView(model as IList);
    return _collectionView;
}

 and the CollectionView

        private IList SourceList
        {
            get { return SourceCollection as IList; }
        }
 
        public new bool CanRemove
        {
            get
            {
                Type itemType = Csla.Utilities.GetChildItemType(this.SourceCollection.GetType());
                if (itemType == null)
                    return false;
 
                IBusinessListBase businessListBase = (this.SourceCollection as IBusinessListBase);
                return Csla.Rules.BusinessRules.HasPermission(Csla.Rules.AuthorizationActions.DeleteObject, itemType)
                    && SourceList.Count > 0 
                    && !businessListBase.IsBusy;
            }
        }
 
        public new bool CanAddNew
        {
            get
            {
                Type itemType = Csla.Utilities.GetChildItemType(this.SourceCollection.GetType());
                if (itemType == null)
                    return false;
 
                IBusinessListBase businessListBase = (this.SourceCollection as IBusinessListBase);
                return Csla.Rules.BusinessRules.HasPermission(Csla.Rules.AuthorizationActions.CreateObject, itemType)
                    && businessListBase.AllowNew
                    && !businessListBase.IsBusy;
            }
        }
 
        public new object AddNew()
        {
            var verifyRefreshNotDeferredMethod = this.GetType().GetMethod("VerifyRefreshNotDeferred"BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod);
            verifyRefreshNotDeferredMethod.Invoke(thisnull);
 
            if (IsEditingItem)
            {
                CommitEdit();   // implicitly close a previous EditItem 
            }
 
            CommitNew();        // implicitly close a previous AddNew 
 
            if (!CanAddNew)
                throw new InvalidOperationException("AddNew is not allowed");
 
            var _newItemIndexProp = this.GetType().BaseType.GetField("_newItemIndex"BindingFlags.NonPublic | BindingFlags.Instance);
            _newItemIndexProp.SetValue(this, -2);  // this is a signal that the next Add event comes from AddNew 
            var newItem = (this.SourceCollection as IObservableBindingList).AddNew();
            int index = (this.SourceCollection as IList).IndexOf(newItem);
 
            // if the source doesn't raise collection change events, fake one 
            if (!(this.SourceCollection is INotifyCollectionChanged))
            {
                // the index returned by IList.Add isn't always reliable
                if (!Object.Equals(newItem, SourceList[index]))
                {
                    index = SourceList.IndexOf(newItem);
                }
                var beginAddNewMethod = this.GetType().GetMethod("BeginAddNew"BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod);
                beginAddNewMethod.Invoke(thisnew object[] {newItem, index} );
            }
 
            MoveCurrentTo(newItem);
 
            ISupportInitialize isi = newItem as ISupportInitialize;
            if (isi != null)
            {
                isi.BeginInit();
            }
 
            IEditableObject ieo = newItem as IEditableObject;
            if (ieo != null)
            {
                ieo.BeginEdit();
            }
 
            return newItem;
        }

Copyright (c) Marimer LLC