Esempio n. 1
0
        public void BlockOpposite(object value, IPropertySerializationInfo property)
        {
            if (property == null || property.Opposite == null)
            {
                return;
            }
            var pair = new ObjectPropertyPair()
            {
                Object = value, Property = property.Opposite
            };

            blockedProperties.Add(pair);
        }
Esempio n. 2
0
        public bool IsOppositeSet(object instance, IPropertySerializationInfo property)
        {
            if (property == null || property.Opposite == null)
            {
                return(false);
            }
            var pair = new ObjectPropertyPair()
            {
                Object = instance, Property = property
            };

            return(blockedProperties.Contains(pair));
        }
Esempio n. 3
0
    /// <summary>
    ///     For complex property paths, we need to dig our way down to the
    /// property and attach the animation clock there.  We will not be able to
    /// actually attach the clocks if the targetProperty points to a frozen
    /// Freezable.  More extensive handling will be required for that case.
    /// </summary>
    private void ProcessComplexPath( HybridDictionary clockMappings, DependencyObject targetObject,
        PropertyPath path, AnimationClock animationClock, HandoffBehavior handoffBehavior, Int64 layer )
    {
        Debug.Assert(path.Length > 1, "This method shouldn't even be called for a simple property path.");

        // For complex paths, the target object/property differs from the actual
        //  animated object/property.
        //
        // Example:
        //  TargetName="Rect1" TargetProperty="(Rectangle.LayoutTransform).(RotateTransform.Angle)"
        //
        // The target object is a Rectangle.
        // The target property is LayoutTransform.
        // The animated object is a RotateTransform
        // The animated property is Angle.

        // Currently unsolved problem: If the LayoutTransform is not a RotateTransform,
        //  we have no way of knowing.  We'll merrily set up to animate the Angle
        //  property as an attached property, not knowing that the value will be
        //  completely ignored.

        DependencyProperty targetProperty   = path.GetAccessor(0) as DependencyProperty;

        // Two different ways to deal with property paths.  If the target is
        //  on a frozen Freezable, we'll have to make a clone of the value and
        //  attach the animation on the clone instead.
        // For all other objects, we attach the animation clock directly on the
        //  specified animating object and property.
        object targetPropertyValue = targetObject.GetValue(targetProperty);

        DependencyObject   animatedObject   = path.LastItem as DependencyObject;
        DependencyProperty animatedProperty = path.LastAccessor as DependencyProperty;

        if( animatedObject == null ||
            animatedProperty == null ||
            targetProperty == null )
        {
            throw new InvalidOperationException(SR.Get(SRID.Storyboard_PropertyPathUnresolved, path.Path));
        }

        VerifyAnimationIsValid(animatedProperty, animationClock);

        if( PropertyCloningRequired( targetPropertyValue ) )
        {
            // Verify that property paths are supported for the specified
            //  object and property.  If the property value query (usually in
            //  GetValueCore) doesn't call into Storyboard code, then none of this
            //  will have any effect.  (Silently do nothing.)
            // Throwing here is for user's sake to alert that nothing will happen.
            VerifyComplexPathSupport( targetObject );

            // We need to clone the value of the target, and from here onwards
            //  try to pretend that it is the actual value.
            Debug.Assert(targetPropertyValue is Freezable, "We shouldn't be trying to clone a type we don't understand.  PropertyCloningRequired() has improperly flagged the current value as 'need to clone'.");

            // To enable animations on frozen Freezable objects, complex
            //  path processing is done on a clone of the value.
            Freezable clone = ((Freezable)targetPropertyValue).Clone();
            SetComplexPathClone( targetObject, targetProperty, targetPropertyValue, clone );

            // Promote the clone to the EffectiveValues cache
            targetObject.InvalidateProperty(targetProperty);

            // We're supposed to have the animatable clone in place by now.  But if
            //  things went sour for whatever reason, halt the app instead of corrupting
            //  the frozen object.
            if( targetObject.GetValue(targetProperty) != clone )
            {
                throw new InvalidOperationException(SR.Get(SRID.Storyboard_ImmutableTargetNotSupported, path.Path));
            }

            // Now that we have a clone, update the animatedObject and animatedProperty
            //  with references to those on the clone.
            using(path.SetContext(targetObject))
            {
                animatedObject = path.LastItem as DependencyObject;
                animatedProperty = path.LastAccessor as DependencyProperty;
            }

            // And set up to listen to changes on this clone.
            ChangeListener.ListenToChangesOnFreezable(
                targetObject, clone, targetProperty, (Freezable)targetPropertyValue );
        }

        // Apply animation clock on the animated object/animated property.
        ObjectPropertyPair directApplyTarget = new ObjectPropertyPair( animatedObject, animatedProperty );
        UpdateMappings( clockMappings, directApplyTarget, animationClock );
    }
Esempio n. 4
0
    /// <summary>
    ///     Given an animation clock, add it to the data structure which tracks
    /// all the clocks along with their associated target object and property.
    /// </summary>
    private static void UpdateMappings(
        HybridDictionary clockMappings,
        ObjectPropertyPair mappingKey,
        AnimationClock animationClock)
    {
        object mappedObject = clockMappings[mappingKey];

        Debug.Assert( mappedObject == null || mappedObject is AnimationClock || mappedObject is List<AnimationClock>,
            "Internal error - clockMappings table contains an unexpected object " + ((mappedObject == null ) ? "" : mappedObject.GetType().ToString()) );

        if( mappedObject == null )
        {
            // No clock currently in storage, put this clock in that slot.
            clockMappings[mappingKey] = animationClock;
        }
        else if( mappedObject is AnimationClock )
        {
            // One clock currently in storage, up-convert to list and replace in slot.
            List<AnimationClock> clockList = new List<AnimationClock>();

            clockList.Add((AnimationClock)mappedObject);
            clockList.Add(animationClock);

            clockMappings[mappingKey] = clockList;
        }
        else // mappedObject is List<AnimationClock>
        {
            // Add to existing list in storage.
            List<AnimationClock> clockList = (List<AnimationClock>)mappedObject;

            clockList.Add(animationClock);
        }

        return;
    }
Esempio n. 5
0
    /// <summary>
    ///     Recursively walks the clock tree and determine the target object
    /// and property for each clock in the tree.
    /// </summary>
    /// <remarks>
    ///     The currently active object and property path are passed in as parameters,
    /// they will be used unless a target/property specification exists on
    /// the Timeline object corresponding to the current clock.  (So that the
    /// leaf-most reference wins.)
    ///
    ///     The active object and property parameters may be null if they have
    /// never been specified.  If we reach a leaf node clock and a needed attribute
    /// is still null, it is an error condition.  Otherwise we keep hoping they'll be found.
    /// </remarks>
    private void ClockTreeWalkRecursive(
        Clock currentClock,                /* No two calls will have the same currentClock     */
        DependencyObject containingObject, /* Remains the same through all the recursive calls */
        INameScope nameScope,              /* Remains the same through all the recursive calls */
        DependencyObject parentObject,
        string parentObjectName,
        PropertyPath parentPropertyPath,
        HandoffBehavior handoffBehavior,   /* Remains the same through all the recursive calls */
        HybridDictionary clockMappings,
        Int64 layer                        /* Remains the same through all the recursive calls */)
    {
        Timeline currentTimeline = currentClock.Timeline;

        DependencyObject targetObject = parentObject;
        string currentObjectName = parentObjectName;
        PropertyPath currentPropertyPath = parentPropertyPath;

        // If we have target object/property information, use it instead of the
        //  parent's information.
        string nameString = (string)currentTimeline.GetValue(TargetNameProperty);
        if( nameString != null )
        {
            if( nameScope is Style )
            {
                // We are inside a Style - we don't let people target anything.
                //  They're only allowed to modify the Styled object, which is
                //  already the implicit target.
                throw new InvalidOperationException(SR.Get(SRID.Storyboard_TargetNameNotAllowedInStyle, nameString));
            }
            currentObjectName = nameString;
        }

        // The TargetProperty trumps the TargetName property.
        DependencyObject localTargetObject = (DependencyObject) currentTimeline.GetValue(TargetProperty);
        if( localTargetObject != null )
        {
            targetObject = localTargetObject;
            currentObjectName = null;
        }

        PropertyPath propertyPath = (PropertyPath)currentTimeline.GetValue(TargetPropertyProperty);
        if( propertyPath != null )
        {
            currentPropertyPath = propertyPath;
        }

        // Now see if the current clock is an animation clock
        if( currentClock is AnimationClock )
        {
            DependencyProperty targetProperty = null;
            AnimationClock animationClock = (AnimationClock)currentClock;

            if( targetObject == null )
            {
                // Resolve the target object name.  If no name specified, use the
                //  containing object.
                if( currentObjectName != null )
                {
                    DependencyObject mentor = Helper.FindMentor(containingObject);

                    targetObject = ResolveTargetName(currentObjectName, nameScope, mentor);
                }
                else
                {
                    // The containing object must be either an FE or FCE.
                    // (Not a Storyboard, as used for "shared clocks" mode.)
                    targetObject = containingObject as FrameworkElement;
                    if(targetObject == null)
                    {
                        targetObject = containingObject as FrameworkContentElement;
                    }

                    if( targetObject == null )
                    {
                        // The containing object is not an FE or FCE.
                        throw new InvalidOperationException(SR.Get(SRID.Storyboard_NoTarget, currentTimeline.GetType().ToString() ));
                    }
                }
            }

            // See if we have a property name to use.
            if( currentPropertyPath == null )
            {
                throw new InvalidOperationException(SR.Get(SRID.Storyboard_TargetPropertyRequired, currentTimeline.GetType().ToString() ));
            }

            // A property name can be a straightforward property name (like "Angle")
            // but may be a more complex multi-step property path.  The two cases
            // are handled differently.
            using(currentPropertyPath.SetContext(targetObject))
            {
                if( currentPropertyPath.Length < 1 )
                {
                    throw new InvalidOperationException(SR.Get(SRID.Storyboard_PropertyPathEmpty));
                }

                VerifyPathIsAnimatable(currentPropertyPath);

                if( currentPropertyPath.Length == 1 )
                {
                    // We have a simple single-step property.
                    targetProperty = currentPropertyPath.GetAccessor(0) as DependencyProperty;

                    if( targetProperty == null )
                    {
                        // Unfortunately it's not a DependencyProperty.
                        throw new InvalidOperationException(SR.Get(SRID.Storyboard_PropertyPathMustPointToDependencyProperty, currentPropertyPath.Path ));
                    }

                    VerifyAnimationIsValid(targetProperty, animationClock);

                    ObjectPropertyPair animatedTarget = new ObjectPropertyPair(targetObject, targetProperty);
                    UpdateMappings(clockMappings, animatedTarget, animationClock);
                }
                else // path.Length > 1
                {
                    // This is a multi-step property path that requires more extensive
                    //  setup.
                    ProcessComplexPath(clockMappings, targetObject, currentPropertyPath, animationClock, handoffBehavior, layer);
                }
            }
        }
        else if ( currentClock is MediaClock ) // Not an animation clock - maybe a media clock?
        {
            // Yes it's a media clock.  Try to find the corresponding object and
            //  apply the clock to that object.
            ApplyMediaClock(nameScope, containingObject, targetObject, currentObjectName, (MediaClock) currentClock);
        }
        else
        {
            // None of the types we recognize as leaf node clock types -
            //  recursively process child clocks.
            ClockGroup currentClockGroup = currentClock as ClockGroup;

            if (currentClockGroup != null)
            {
                ClockCollection childrenClocks = currentClockGroup.Children;

                for( int i = 0; i < childrenClocks.Count; i++ )
                {
                    ClockTreeWalkRecursive(
                        childrenClocks[i],
                        containingObject,
                        nameScope,
                        targetObject,
                        currentObjectName,
                        currentPropertyPath,
                        handoffBehavior,
                        clockMappings,
                        layer);
                }
            }
        }
    }
Esempio n. 6
0
 public bool Equals(ObjectPropertyPair key)
 {
     return (_object.Equals(key._object) && (_property == key._property));
 }