Example #1
0
        private object GetCollectionInstance(ClientPropertyAnnotation property, out bool instanceCreated)
        {
            instanceCreated = false;
            object obj2 = property.GetValue(this.entity);

            if (obj2 != null)
            {
                return(obj2);
            }
            instanceCreated = true;
            Type propertyType = property.PropertyType;

            if (BindingEntityInfo.IsDataServiceCollection(propertyType, base.RequestInfo.MaxProtocolVersion))
            {
                object[] args = new object[2];
                args[1] = TrackingMode.None;
                return(Activator.CreateInstance(WebUtil.GetDataServiceCollectionOfT(new Type[] { property.EntityCollectionItemType }), args));
            }
            Type c = typeof(List <>).MakeGenericType(new Type[] { property.EntityCollectionItemType });

            if (!propertyType.IsAssignableFrom(c))
            {
                c = propertyType;
            }
            return(Activator.CreateInstance(c));
        }
Example #2
0
        internal static void VerifyObserverNotPresent <T>(object oec, string sourceProperty, Type sourceType)
        {
            Debug.Assert(BindingEntityInfo.IsDataServiceCollection(oec.GetType()), "Must be an DataServiceCollection.");

            DataServiceCollection <T> typedCollection = oec as DataServiceCollection <T>;

            if (typedCollection.Observer != null)
            {
                throw new InvalidOperationException(Strings.DataBinding_CollectionPropertySetterValueHasObserver(sourceProperty, sourceType));
            }
        }
Example #3
0
        /// <summary>
        /// Determine if the specified type is an entity type.
        /// </summary>
        /// <param name="type">An object type specifier.</param>
        /// <param name="model">The client model.</param>
        /// <returns>true if the type is an entity type; otherwise false.</returns>
        internal static bool IsEntityType(Type type, ClientEdmModel model)
        {
            Debug.Assert(type != null, "Argument 'type' cannot be null.");

            metadataCacheLock.EnterReadLock();
            try
            {
                if (knownNonEntityTypes.Contains(type))
                {
                    return(false);
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            bool isEntityType;

            try
            {
                if (BindingEntityInfo.IsDataServiceCollection(type, model))
                {
                    return(false);
                }

                isEntityType = ClientTypeUtil.TypeOrElementTypeIsEntity(type);
            }
            catch (InvalidOperationException)
            {
                isEntityType = false;
            }

            if (!isEntityType)
            {
                metadataCacheLock.EnterWriteLock();
                try
                {
                    if (!knownNonEntityTypes.Contains(type))
                    {
                        knownNonEntityTypes.Add(type);
                    }
                }
                finally
                {
                    metadataCacheLock.ExitWriteLock();
                }
            }

            return(isEntityType);
        }
        /// <summary>
        /// Determine if the specified type is an entity type.
        /// </summary>
        /// <param name="type">An object type specifier.</param>
        /// <returns>True if the type is an entity type; otherwise false.</returns>
        internal static bool IsEntityType(Type type)
        {
            Debug.Assert(type != null, "Argument 'type' cannot be null.");

            metadataCacheLock.EnterReadLock();
            try
            {
                if (knownNonEntityTypes.Contains(type))
                {
                    return(false);
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            try
            {
                if (BindingEntityInfo.IsDataServiceCollection(type))
                {
                    return(false);
                }

                return(ClientType.Create(type).IsEntityType);
            }
            catch (InvalidOperationException)
            {
                metadataCacheLock.EnterWriteLock();
                try
                {
                    if (!knownNonEntityTypes.Contains(type))
                    {
                        knownNonEntityTypes.Add(type);
                    }
                }
                finally
                {
                    metadataCacheLock.ExitWriteLock();
                }

                return(false);
            }
        }
Example #5
0
        internal void OnCollectionChanged(object collection, NotifyCollectionChangedEventArgs eventArgs)
        {
            Util.CheckArgumentNull(collection, "collection");
            Util.CheckArgumentNull(eventArgs, "eventArgs");

            Debug.Assert(BindingEntityInfo.IsDataServiceCollection(collection.GetType()), "We only register this event for DataServiceCollections.");
#if DEBUG
            Debug.Assert(this.bindingGraph.IsTracking(collection), "Collection must be part of the graph if it has the event notification registered.");
#endif
            object source;
            string sourceProperty;
            string sourceEntitySet;
            string targetEntitySet;

            this.bindingGraph.GetEntityCollectionInfo(
                collection,
                out source,
                out sourceProperty,
                out sourceEntitySet,
                out targetEntitySet);

            switch (eventArgs.Action)
            {
            case NotifyCollectionChangedAction.Add:
                this.OnAddToCollection(
                    eventArgs,
                    source,
                    sourceProperty,
                    targetEntitySet,
                    collection);
                break;

            case NotifyCollectionChangedAction.Remove:
                this.OnDeleteFromCollection(
                    eventArgs,
                    source,
                    sourceProperty,
                    collection);
                break;

            case NotifyCollectionChangedAction.Replace:
                this.OnDeleteFromCollection(
                    eventArgs,
                    source,
                    sourceProperty,
                    collection);

                this.OnAddToCollection(
                    eventArgs,
                    source,
                    sourceProperty,
                    targetEntitySet,
                    collection);
                break;

            case NotifyCollectionChangedAction.Reset:
                if (this.DetachBehavior)
                {
                    this.RemoveWithDetachCollection(collection);
                }
                else
                {
                    this.bindingGraph.RemoveCollection(collection);
                }

                break;

#if !ASTORIA_LIGHT
            case NotifyCollectionChangedAction.Move:
                break;
#endif

            default:
                throw new InvalidOperationException(Strings.DataBinding_CollectionChangedUnknownAction(eventArgs.Action));
            }
        }
Example #6
0
        public bool AddCollection(
            object source,
            string sourceProperty,
            object collection,
            string collectionEntitySet)
        {
            Debug.Assert(collection != null, "'collection' can not be null");
            Debug.Assert(
                BindingEntityInfo.IsDataServiceCollection(collection.GetType()),
                "Argument 'collection' must be an DataServiceCollection<T> of entity type T");

            if (this.graph.ExistsVertex(collection))
            {
                return(false);
            }

            Vertex collectionVertex = this.graph.AddVertex(collection);

            collectionVertex.IsCollection = true;
            collectionVertex.EntitySet    = collectionEntitySet;

            ICollection collectionItf = collection as ICollection;

            if (source != null)
            {
                collectionVertex.Parent         = this.graph.LookupVertex(source);
                collectionVertex.ParentProperty = sourceProperty;
                this.graph.AddEdge(source, collection, sourceProperty);

                Type entityType = BindingUtils.GetCollectionEntityType(collection.GetType());
                Debug.Assert(entityType != null, "Collection must at least be inherited from DataServiceCollection<T>");

                if (!typeof(INotifyPropertyChanged).IsAssignableFrom(entityType))
                {
                    throw new InvalidOperationException(Strings.DataBinding_NotifyPropertyChangedNotImpl(entityType));
                }

                typeof(BindingGraph)
                .GetMethod("SetObserver", BindingFlags.Instance | BindingFlags.NonPublic)
                .MakeGenericMethod(entityType)
                .Invoke(this, new object[] { collectionItf });
            }
            else
            {
                this.graph.Root = collectionVertex;
            }

            Debug.Assert(
                collectionVertex.Parent != null || collectionVertex.IsRootCollection,
                "If parent is null, then collectionVertex should be a root collection");

            this.AttachCollectionNotification(collection);

            foreach (var item in collectionItf)
            {
                this.AddEntity(
                    source,
                    sourceProperty,
                    item,
                    collectionEntitySet,
                    collection);
            }

            return(true);
        }
Example #7
0
        /// <summary>Obtain binding info corresponding to a given type</summary>
        /// <param name="entityType">Type for which to obtain information</param>
        /// <param name="model">The client model.</param>
        /// <returns>Info about the <paramref name="entityType"/></returns>
        private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType, ClientEdmModel model)
        {
            BindingEntityInfoPerType bindingEntityInfo;

            metadataCacheLock.EnterReadLock();
            try
            {
                if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
                {
                    return(bindingEntityInfo);
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            bindingEntityInfo = new BindingEntityInfoPerType();

            // Try to get the entity set name from the EntitySetAttribute attributes. In order to make the
            // inheritance work, we need to look at the attributes declared in the base types also.
            // EntitySetAttribute does not allow multiples, so there can be at most 1 instance on the type.
            EntitySetAttribute entitySetAttribute = (EntitySetAttribute)entityType.GetCustomAttributes(typeof(EntitySetAttribute), true).SingleOrDefault();

            // There must be exactly one (unambiguous) EntitySetAttribute attribute.
            bindingEntityInfo.EntitySet  = entitySetAttribute != null ? entitySetAttribute.EntitySet : null;
            bindingEntityInfo.ClientType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityType));

            foreach (ClientPropertyAnnotation p in bindingEntityInfo.ClientType.Properties())
            {
                BindingPropertyInfo bpi = null;
                Type propertyType       = p.PropertyType;

                if (p.IsStreamLinkProperty)
                {
                    // DataServiceStreamLink is not mutable externally
                    // It implements INPC to notify controls about our updates
                    // We should ignore its events since we are the only one updating it.
                    continue;
                }
                else if (p.IsPrimitiveOrComplexCollection)
                {
                    Debug.Assert(!BindingEntityInfo.IsDataServiceCollection(propertyType, model), "DataServiceCollection cannot be the type that backs collections of primitives or complex types.");
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindPrimitiveOrComplexCollection
                    };
                }
                else if (p.IsEntityCollection)
                {
                    if (BindingEntityInfo.IsDataServiceCollection(propertyType, model))
                    {
                        bpi = new BindingPropertyInfo {
                            PropertyKind = BindingPropertyKind.BindingPropertyKindDataServiceCollection
                        };
                    }
                }
                else if (BindingEntityInfo.IsEntityType(propertyType, model))
                {
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindEntity
                    };
                }
                else if (BindingEntityInfo.CanBeComplexType(propertyType))
                {
                    // Add complex types and nothing else.
                    Debug.Assert(!p.IsKnownType, "Known types do not implement INotifyPropertyChanged.");
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindComplex
                    };
                }

                if (bpi != null)
                {
                    bpi.PropertyInfo = p;

                    // For entity types, all of the above types of properties are interesting.
                    // For complex types, only observe collections and complex type properties.
                    if (bindingEntityInfo.ClientType.IsEntityType ||
                        bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex ||
                        bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindPrimitiveOrComplexCollection)
                    {
                        bindingEntityInfo.ObservableProperties.Add(bpi);
                    }
                }
            }

            metadataCacheLock.EnterWriteLock();
            try
            {
                if (!bindingEntityInfos.ContainsKey(entityType))
                {
                    bindingEntityInfos[entityType] = bindingEntityInfo;
                }
            }
            finally
            {
                metadataCacheLock.ExitWriteLock();
            }

            return(bindingEntityInfo);
        }
        /// <summary>Obtain binding info corresponding to a given type</summary>
        /// <param name="entityType">Type for which to obtain information</param>
        /// <returns>Info about the <paramref name="entityType"/></returns>
        private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType)
        {
            BindingEntityInfoPerType bindingEntityInfo;

            metadataCacheLock.EnterReadLock();
            try
            {
                if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
                {
                    return(bindingEntityInfo);
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            bindingEntityInfo = new BindingEntityInfoPerType();

            // Try to get the entity set name from the EntitySetAttribute attributes. In order to make the
            // inheritance work, we need to look at the attributes declared in the base types also.
            object[] attributes = entityType.GetCustomAttributes(typeof(EntitySetAttribute), true);

            // There must be exactly one (unambiguous) EntitySetAttribute attribute.
            bindingEntityInfo.EntitySet  = (attributes != null && attributes.Length == 1) ? ((EntitySetAttribute)attributes[0]).EntitySet : null;
            bindingEntityInfo.ClientType = ClientType.Create(entityType);

            foreach (ClientType.ClientProperty p in bindingEntityInfo.ClientType.Properties)
            {
                BindingPropertyInfo bpi = null;

                Type propertyType = p.PropertyType;

                if (p.CollectionType != null)
                {
                    if (BindingEntityInfo.IsDataServiceCollection(propertyType))
                    {
                        bpi = new BindingPropertyInfo {
                            PropertyKind = BindingPropertyKind.BindingPropertyKindCollection
                        };
                    }
                }
                else
                if (BindingEntityInfo.IsEntityType(propertyType))
                {
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindEntity
                    };
                }
                else
                if (BindingEntityInfo.CanBeComplexProperty(p))
                {
                    // Add complex types and nothing else.
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindComplex
                    };
                }

                if (bpi != null)
                {
                    bpi.PropertyInfo = p;

                    // For complex types only treat complex typed properties as observable, we are not going to observer entity typed or primitive properties.
                    if (bindingEntityInfo.ClientType.IsEntityType || bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex)
                    {
                        bindingEntityInfo.ObservableProperties.Add(bpi);
                    }
                }
            }

            metadataCacheLock.EnterWriteLock();
            try
            {
                if (!bindingEntityInfos.ContainsKey(entityType))
                {
                    bindingEntityInfos[entityType] = bindingEntityInfo;
                }
            }
            finally
            {
                metadataCacheLock.ExitWriteLock();
            }

            return(bindingEntityInfo);
        }
        /// <summary>Handle changes to tracked DataServiceCollection.</summary>
        /// <param name="collection">The DataServiceCollection that raised the event.</param>
        /// <param name="eventArgs">Information about the event such as added/removed entities, operation.</param>
        internal void OnCollectionChanged(object collection, NotifyCollectionChangedEventArgs eventArgs)
        {
            Util.CheckArgumentNull(collection, "collection");
            Util.CheckArgumentNull(eventArgs, "eventArgs");

            Debug.Assert(BindingEntityInfo.IsDataServiceCollection(collection.GetType()), "We only register this event for DataServiceCollections.");
#if DEBUG
            Debug.Assert(this.bindingGraph.IsTracking(collection), "Collection must be part of the graph if it has the event notification registered.");
#endif
            object source;
            string sourceProperty;
            string sourceEntitySet;
            string targetEntitySet;

            this.bindingGraph.GetEntityCollectionInfo(
                collection,
                out source,
                out sourceProperty,
                out sourceEntitySet,
                out targetEntitySet);

            switch (eventArgs.Action)
            {
            case NotifyCollectionChangedAction.Add:
                // This event is raised by ObservableCollection.InsertItem.
                this.OnAddToCollection(
                    eventArgs,
                    source,
                    sourceProperty,
                    targetEntitySet,
                    collection);
                break;

            case NotifyCollectionChangedAction.Remove:
                // This event is raised by ObservableCollection.RemoveItem.
                this.OnDeleteFromCollection(
                    eventArgs,
                    source,
                    sourceProperty,
                    collection);
                break;

            case NotifyCollectionChangedAction.Replace:
                // This event is raised by ObservableCollection.SetItem.
                this.OnDeleteFromCollection(
                    eventArgs,
                    source,
                    sourceProperty,
                    collection);

                this.OnAddToCollection(
                    eventArgs,
                    source,
                    sourceProperty,
                    targetEntitySet,
                    collection);
                break;

            case NotifyCollectionChangedAction.Reset:
                // This event is raised by ObservableCollection.Clear.
                if (this.DetachBehavior)
                {
                    // Detach behavior requires going through each item and detaching it from context.
                    this.RemoveWithDetachCollection(collection);
                }
                else
                {
                    // Non-detach behavior requires only removing vertices of collection from graph.
                    this.bindingGraph.RemoveCollection(collection);
                }

                break;

#if !ASTORIA_LIGHT
            case NotifyCollectionChangedAction.Move:
                // Do Nothing. Added for completeness.
                break;
#endif

            default:
                throw new InvalidOperationException(Strings.DataBinding_CollectionChangedUnknownAction(eventArgs.Action));
            }
        }
Example #10
0
        private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType)
        {
            BindingEntityInfoPerType bindingEntityInfo;

            metadataCacheLock.EnterReadLock();
            try
            {
                if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
                {
                    return(bindingEntityInfo);
                }
            }
            finally
            {
                metadataCacheLock.ExitReadLock();
            }

            bindingEntityInfo = new BindingEntityInfoPerType();

            object[] attributes = entityType.GetCustomAttributes(typeof(EntitySetAttribute), true);

            bindingEntityInfo.EntitySet  = (attributes != null && attributes.Length == 1) ? ((EntitySetAttribute)attributes[0]).EntitySet : null;
            bindingEntityInfo.ClientType = ClientType.Create(entityType);

            foreach (ClientType.ClientProperty p in bindingEntityInfo.ClientType.Properties)
            {
                BindingPropertyInfo bpi = null;

                Type propertyType = p.PropertyType;

                if (p.CollectionType != null)
                {
                    if (BindingEntityInfo.IsDataServiceCollection(propertyType))
                    {
                        bpi = new BindingPropertyInfo {
                            PropertyKind = BindingPropertyKind.BindingPropertyKindCollection
                        };
                    }
                }
                else
                if (BindingEntityInfo.IsEntityType(propertyType))
                {
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindEntity
                    };
                }
                else
                if (BindingEntityInfo.CanBeComplexProperty(p))
                {
                    bpi = new BindingPropertyInfo {
                        PropertyKind = BindingPropertyKind.BindingPropertyKindComplex
                    };
                }

                if (bpi != null)
                {
                    bpi.PropertyInfo = p;

                    if (bindingEntityInfo.ClientType.IsEntityType || bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex)
                    {
                        bindingEntityInfo.ObservableProperties.Add(bpi);
                    }
                }
            }

            metadataCacheLock.EnterWriteLock();
            try
            {
                if (!bindingEntityInfos.ContainsKey(entityType))
                {
                    bindingEntityInfos[entityType] = bindingEntityInfo;
                }
            }
            finally
            {
                metadataCacheLock.ExitWriteLock();
            }

            return(bindingEntityInfo);
        }