Beispiel #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="T:UsedProperty"/> class.
        /// </summary>
        internal UsedPropertyChain(INotifyPropertyChanged parent, string name, UsedSubproperty child,
                                   TraversalOptions traversalOptions)
            : base(name, child, traversalOptions)
        {
            if (parent == null)
            {
                throw new ArgumentNullException("target");
            }

            this.Parent         = parent;
            this.TopLevelParent = this;
        }
Beispiel #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="T:UsePropertyBase"/> class.
        /// </summary>
        internal UsedPropertyBase(string name, UsedSubproperty child,
                                  TraversalOptions traversalOptions)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }

            this.Child             = child;
            this.Name              = name;
            this.tracedItems       = new List <INotifyPropertyChanged>();
            this.TraversalOptions  = traversalOptions;
            this.cyclicAccessGuard = new CyclicAccessGuard <AccessTrace>(1, cyclicAccessRecord);
        }
Beispiel #3
0
        private static UsedSubproperty GetContinuationChainLink(
            MemberExpression memberExpression,
            ChildInformation child,
            TraversalOptions options)
        {
            Func <INotifyPropertyChanged> parentRetriever =
                CompileObjectFactoryExpressionINPC(memberExpression.Expression);

            if (parentRetriever == null)
            {
                //This happens when parentMember refers to a non-observable collection
                return(null);
            }
            var usedSub = new UsedSubproperty(memberExpression.Member.Name, parentRetriever,
                                              child.Property, options);

            usedSub.TargetRetriever = CompileMemberExpression(memberExpression);
            return(usedSub);
        }
Beispiel #4
0
        private static void GetUsedProperties(Set <UsedPropertyChain> container,
                                              MemberExpression memberExpression,
                                              ChildInformation child,
                                              TraversalOptions options)
        {
            if (memberExpression == null)
            {
                return;
            }
            MemberTypes memberType = memberExpression.Member.MemberType;

            if (memberType != MemberTypes.Property)
            {
                if (memberType == MemberTypes.Field)
                {
                    if (options.TrackFields)
                    {
                        var constant = memberExpression.Expression as ConstantExpression;
                        if (constant != null)
                        {
                            HandleFieldConstant(container, memberExpression, child, options);
                            return;
                        }

                        if (IsFieldChain(memberExpression) && child.IsTrackable)
                        {
                            //Occurs with a.b.c.A kind of expression, where
                            //the field chain is the leading part of the
                            //expression and the constant can be extracted from
                            //it. The constant is taken from evaluation of a.b.c

                            HandleFieldConstant(container, memberExpression, child, options);
                            return;
                        }
                        else
                        {
                            //Dead end. It happens, when a field occurs
                            //after a non-constant element, e.g. after
                            //a property reference as in 'A.B.field.C'
                            //'A.B' is not ConstantExpression and therefore,
                            //even with TrackFields on, the field cannot be
                            //tracked any further. However, the preceding
                            //part of the expression can and should be
                            //tracked.

                            //Break the chain (without continuation)
                            GetUsedProperties(container, memberExpression.Expression, ChildInformation.FieldBreak, options);
                            return;
                        }
                    }
                    else
                    {
                        //Break the chain (without continuation)
                        GetUsedProperties(container, memberExpression.Expression, ChildInformation.FieldBreak, options);
                        return;
                    }
                }

                throw new InvalidOperationException("Unhandled case. Revise the code");
            }

            var parentMember = memberExpression.Expression as MemberExpression;

            if (parentMember != null)
            {
                UsedSubproperty usedSubProperty = GetContinuationChainLink(memberExpression, child, options);
                var             usedChild       = new ChildInformation(usedSubProperty);
                //Continue the chain
                GetUsedProperties(container, parentMember, usedChild, options);
            }
            else
            {
                if (memberExpression.Expression is ParameterExpression)
                {
                    //Presumably, we are within a nested lambda parameter block.
                    //Skip, just for now. If there's a nested lambda like "c=>c.property" it
                    //is pretty complicated to know when to update.
                    //TODO:
                    return;
                }

                var constant = memberExpression.Expression as ConstantExpression;
                if (constant != null)
                {
                    var notifiable = constant.Value as INotifyPropertyChanged;
                    if (notifiable != null)
                    {
                        string propertyName = memberExpression.Member.Name;
                        var    chain        = new UsedPropertyChain(notifiable, propertyName, child.Property, options);
                        chain.TargetRetriever = CompileMemberExpression(memberExpression);
                        container.Add(chain);
                    }
                    else
                    {
                        //Even now add a chain to the container. Fields are not traced, but their
                        //properties can be. This applies only to cases where a the left-hand part
                        //of an expression is a field or a field/constant chain.
                        HandleFieldConstant(container, memberExpression, child, options);
                    }
                    return;
                }
                else
                {
                    UsedSubproperty usedSubProperty = GetContinuationChainLink(memberExpression, child, options);
                    var             usedChild       = new ChildInformation(usedSubProperty);

                    //This should break the notification chain or continue, if it's marker method.
                    GetUsedProperties(container, memberExpression.Expression, usedChild, options);
                }
            }
        }
Beispiel #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="T:UsedSubproperty"/> class.
        /// </summary>
        internal UsedSubproperty(string name, Func <INotifyPropertyChanged> parentRetriever, UsedSubproperty child,
                                 TraversalOptions traversalOptions)
            : base(name, child, traversalOptions)
        {
            if (parentRetriever == null)
            {
                throw new ArgumentNullException("parentRetriever");
            }

            this.parentRetriever = parentRetriever;
        }
Beispiel #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="T:ChildInformation"/> class.
 /// </summary>
 public ChildInformation(MemberTypes childMemberType)
 {
     this.MemberType = childMemberType;
     this.Property   = null;
 }
Beispiel #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="T:ChildInformation"/> class.
 /// </summary>
 public ChildInformation(UsedSubproperty subProperty)
 {
     this.Property   = subProperty;
     this.MemberType = subProperty == null ? MemberTypeUnknown : MemberTypes.Property;
 }