// Given a multi data trigger and associated context information,
        //  evaluate the old and new states of the trigger.

        // The short-circuit logic of multi property trigger applies here too.
        //  we bail if any of the "other" conditions evaluate to false.
        private static void EvaluateOldNewStates( MultiDataTrigger multiDataTrigger,
            DependencyObject triggerContainer,
            BindingBase binding, BindingValueChangedEventArgs changedArgs, UncommonField<HybridDictionary[]> dataField,
            Style style, FrameworkTemplate frameworkTemplate,
            out bool oldState, out bool newState )
        {
            BindingBase evaluationBinding = null;
            object  evaluationValue = null;
            TriggerCondition[] conditions = multiDataTrigger.TriggerConditions;

            // Set up the default condition: A trigger with no conditions will never evaluate to true.
            oldState = false;
            newState = false;

            for( int i = 0; i < multiDataTrigger.Conditions.Count; i++ )
            {
                evaluationBinding = conditions[i].Binding;

                Debug.Assert( evaluationBinding != null,
                    "A null binding was encountered in a MultiDataTrigger conditions collection - this is invalid input and should have been caught earlier.");

                if( evaluationBinding == binding )
                {
                    // The binding that changed belonged to the current condition.
                    oldState = conditions[i].ConvertAndMatch(changedArgs.OldValue);
                    newState = conditions[i].ConvertAndMatch(changedArgs.NewValue);

                    if( oldState == newState )
                    {
                        // There couldn't possibly be a transition here, abort.  The
                        //  returned values here aren't necessarily the state of the
                        //  triggers, but we only care about a transition today.  If
                        //  we care about actual values, we'll need to continue evaluation.
                        return;
                    }
                }
                else
                {
                    evaluationValue = GetDataTriggerValue(dataField, triggerContainer, evaluationBinding);
                    if( !conditions[i].ConvertAndMatch(evaluationValue) )
                    {
                        // A condition other than the one changed has evaluated to false.
                        // There couldn't possibly be a transition here, short-circuit and abort.
                        oldState = false;
                        newState = false;
                        return;
                    }
                }
            }

            // We should only get this far only if the binding change causes
            //  a true->false (or vice versa) transition in one of the conditions,
            // AND that every other condition evaluated to true.
            return;
        }
        // Given a single data trigger and associated context information,
        //  evaluate the old and new states of the trigger.
        private static void EvaluateOldNewStates( DataTrigger dataTrigger,
            DependencyObject triggerContainer,
            BindingBase binding, BindingValueChangedEventArgs bindingChangedArgs, UncommonField<HybridDictionary[]> dataField,
            Style style, FrameworkTemplate frameworkTemplate,
            out bool oldState, out bool newState )
        {
            TriggerCondition[] conditions = dataTrigger.TriggerConditions;
            Debug.Assert( conditions != null && conditions.Length == 1,
                "This method assumes there is exactly one TriggerCondition." );

            oldState = conditions[0].ConvertAndMatch(bindingChangedArgs.OldValue);
            newState = conditions[0].ConvertAndMatch(bindingChangedArgs.NewValue);
        }
        // Called from either the Style-specific ExecuteOnApplyEnterActions or the
        //  Template-specific version.  This section is the common code for both that
        //  walks through the trigger collection and execute applicable actions.
        private static void ExecuteOnApplyEnterExitActionsLoop( DependencyObject triggerContainer, TriggerCollection triggers,
            Style style, FrameworkTemplate ft, UncommonField<HybridDictionary[]> dataField )
        {
            TriggerBase triggerBase;
            bool triggerState;
            for( int i = 0; i < triggers.Count; i++ )
            {
                triggerBase = triggers[i];
                if( (!triggerBase.HasEnterActions) && (!triggerBase.HasExitActions) )
                {
                    ; // Trigger has neither enter nor exit actions.  There's nothing to run anyway, so skip.
                }
                else if( triggerBase.ExecuteEnterActionsOnApply ||
                    triggerBase.ExecuteExitActionsOnApply )
                {
                    // Look for any SourceName in the condition
                    if( NoSourceNameInTrigger( triggerBase ) )
                    {
                        // Evaluate the current state of the trigger.
                        triggerState = triggerBase.GetCurrentState( triggerContainer, dataField );

                        if( triggerState && triggerBase.ExecuteEnterActionsOnApply )
                        {
                            // Trigger is true, and Trigger wants EnterActions to be executed on Style/Template application.
                            InvokeActions( triggerBase.EnterActions, triggerBase, triggerContainer,
                                style, ft );
                        }
                        else if( !triggerState && triggerBase.ExecuteExitActionsOnApply )
                        {
                            // Trigger is false, and Trigger wants ExitActions to be executed on Style/Template application.
                            InvokeActions( triggerBase.ExitActions, triggerBase, triggerContainer,
                                style, ft );
                        }
                    }
                    else
                    {
                        // If one or more conditions are dependent on a template
                        //  child, then it can't possibly apply immediately.
                    }
                }
            }
        }
        //
        //  This method
        //  1. Is called whenever a new Style/Template is applied to an FE/FCE
        //  2. It adds per-instance StyleData/TemplateData for the new Style/Template
        //
        internal static void CreateInstanceData(
            UncommonField<HybridDictionary[]> dataField,
            DependencyObject            container,
            FrameworkElement            fe,
            FrameworkContentElement     fce,
            Style                       newStyle,
            FrameworkTemplate           newFrameworkTemplate )
        {
            Debug.Assert((fe != null && fce == null) || (fe == null && fce != null));
            Debug.Assert((fe != null && fe == container) || (fce != null && fce == container));
            Debug.Assert(newStyle != null || newFrameworkTemplate != null );

            if (newStyle != null)
            {
                if (newStyle.HasInstanceValues)
                {
                    HybridDictionary instanceValues = EnsureInstanceData(dataField, container, InstanceStyleData.InstanceValues);
                    StyleHelper.ProcessInstanceValuesForChild(
                        container, container, 0, instanceValues, true,
                        ref newStyle.ChildRecordFromChildIndex);
                }
            }
            else if (newFrameworkTemplate != null)
            {
                if (newFrameworkTemplate.HasInstanceValues)
                {
                    HybridDictionary instanceValues = EnsureInstanceData(dataField, container, InstanceStyleData.InstanceValues);
                    StyleHelper.ProcessInstanceValuesForChild(
                        container, container, 0, instanceValues, true,
                        ref newFrameworkTemplate.ChildRecordFromChildIndex);
                }
            }
        }
Example #5
0
        // evaluate the current state of the trigger
        internal override bool GetCurrentState(DependencyObject container, UncommonField<HybridDictionary[]> dataField) 
        { 
            bool retVal = (TriggerConditions.Length > 0);
 
            for( int i = 0; retVal && i < TriggerConditions.Length; i++ )
            {
                Debug.Assert( TriggerConditions[i].SourceChildIndex == 0,
                    "This method was created to handle properties on the containing object, more work is needed to handle templated children too." ); 

                retVal = TriggerConditions[i].Match(container.GetValue(TriggerConditions[i].Property)); 
            } 

            return retVal; 
        }
Example #6
0
        // The ordering of how things are created and which methods are called are ABSOLUTELY critical
        // Getting this order slightly off will result in several issues that are very hard to debug.
        //
        // The order must be:
        //      Register name to the TemplateNameScope (Either the real name specified by x:Name or
        //              RuntimeNameProperty or a fake name that we have to generate to call
        //              RegisterName.  This is CRUCIAL since RegisterName sets the TemplatedParent
        //              and the TemplateChildIndex on the object
        //      If we're dealing with the root, wire the object to the parent (via FE.TemplateChild
        //          if we're dealing with an FE as the container or using FEF if it's not an FE)
        //      Invalidate properties on the object
        private DependencyObject LoadOptimizedTemplateContent(DependencyObject container,
            IComponentConnector componentConnector,
            IStyleConnector styleConnector, List<DependencyObject> affectedChildren, UncommonField<Hashtable> templatedNonFeChildrenField)
        {
            if (Names == null)
            {
                Names = new XamlContextStack<Frame>(() => new Frame());
            }
            DependencyObject rootObject = null;

            if (TraceMarkup.IsEnabled)
            {
                TraceMarkup.Trace(TraceEventType.Start, TraceMarkup.Load);
            }

            FrameworkElement feContainer = container as FrameworkElement;
            bool isTemplatedParentAnFE = feContainer != null;

            TemplateNameScope nameScope = new TemplateNameScope(container, affectedChildren, this);
            XamlObjectWriterSettings settings = System.Windows.Markup.XamlReader.CreateObjectWriterSettings(_templateHolder.ObjectWriterParentSettings);
            settings.ExternalNameScope = nameScope;
            settings.RegisterNamesOnExternalNamescope = true;

            IEnumerator<String> nameEnumerator = ChildNames.GetEnumerator();

            // Delegate for AfterBeginInit event
            settings.AfterBeginInitHandler =
                delegate(object sender, System.Xaml.XamlObjectEventArgs args)
                {
                    HandleAfterBeginInit(args.Instance, ref rootObject, container, feContainer, nameScope, nameEnumerator);
                    if (XamlSourceInfoHelper.IsXamlSourceInfoEnabled)
                    {
                        XamlSourceInfoHelper.SetXamlSourceInfo(args.Instance, args, null);
                    }
                };
            // Delegate for BeforeProperties event
            settings.BeforePropertiesHandler =
                delegate(object sender, System.Xaml.XamlObjectEventArgs args)
                {
                    HandleBeforeProperties(args.Instance, ref rootObject, container, feContainer, nameScope);
                };
            // Delegate for XamlSetValue event
            settings.XamlSetValueHandler =
                delegate(object sender, System.Windows.Markup.XamlSetValueEventArgs setArgs)
            {
                setArgs.Handled = ReceivePropertySet(sender, setArgs.Member, setArgs.Value, container);
            };

            XamlObjectWriter objectWriter = _templateHolder.ObjectWriterFactory.GetXamlObjectWriter(settings);

            try
            {
                LoadTemplateXaml(objectWriter);
            }
            finally
            {
                if (TraceMarkup.IsEnabled)
                {
                    TraceMarkup.Trace(TraceEventType.Stop, TraceMarkup.Load, rootObject);
                }
            }
            return rootObject;
        }
        // Instantiate a tree.  This is a recursive routine that will build the
        //  subtree via calls to itself.  The root node being instantiated will
        //  have identical references for the "container" and "parent" parameters.
        // The "affectedChildren" and "noChildIndexChildren" parameters refer to the children
        //  chain for the "container" object.  This chain will have all the
        //  children - not just the immediate children.  The node being
        //  instantiated here will be added to this chain.
        // The tree is instantiated in a depth-first traversal, so children nodes
        //  are added to the chain in depth-first order as well.
        //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647
        internal DependencyObject InstantiateTree(
                UncommonField<HybridDictionary[]>           dataField,
                DependencyObject                            container,
                DependencyObject                            parent,
                List<DependencyObject>                      affectedChildren,
            ref List<DependencyObject>                      noChildIndexChildren,
            ref FrugalStructList<ChildPropertyDependent>    resourceDependents)
        {
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose, EventTrace.Event.WClientParseFefCrInstBegin);

            FrameworkElement containerAsFE = container as FrameworkElement;
            bool isContainerAnFE = containerAsFE != null;

            DependencyObject treeNode = null;
            // If we have text, just add it to the parent.  Otherwise create the child
            // subtree
            if (_text != null)
            {
                // of FrameworkContentElement parent.  This is the logical equivalent
                // to what happens when adding a child to a visual collection.
                IAddChild addChildParent = parent as IAddChild;

                if (addChildParent == null)
                {
                    throw new InvalidOperationException(SR.Get(SRID.TypeMustImplementIAddChild,
                                                         parent.GetType().Name));
                }
                else
                {
                    addChildParent.AddText(_text);
                }
            }
            else
            {
                // Factory create instance
                treeNode = CreateDependencyObject();

                EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose, EventTrace.Event.WClientParseFefCrInstEnd);

                // The tree node is either a FrameworkElement or a FrameworkContentElement.
                //  we'll deal with one or the other...
                FrameworkObject treeNodeFO = new FrameworkObject(treeNode);

                Visual3D treeNodeVisual3D = null;
                bool treeNodeIsVisual3D = false;

                if (!treeNodeFO.IsValid)
                {
                    // If it's neither of those, we have special support for Visual3D

                    treeNodeVisual3D = treeNode as Visual3D;
                    if (treeNodeVisual3D != null)
                        treeNodeIsVisual3D = true;
                }

                Debug.Assert( treeNodeFO.IsValid || (treeNodeVisual3D != null),
                    "We should not be trying to instantiate a node that is neither FrameworkElement nor FrameworkContentElement.  A type check should have been done when Type is set");

                // And here's the bool we'll use to make the decision.
                bool treeNodeIsFE = treeNodeFO.IsFE;

                // Handle FE/FCE-specific optimizations

                if (!treeNodeIsVisual3D)
                {
                    // Postpone "Initialized" event
                    NewNodeBeginInit( treeNodeIsFE, treeNodeFO.FE, treeNodeFO.FCE );

                    // Set the resource reference flags
                    if (StyleHelper.HasResourceDependentsForChild(_childIndex, ref resourceDependents))
                    {
                        treeNodeFO.HasResourceReference = true;
                    }

                    // Update the two chains that tracks all the nodes created
                    //  from all the FrameworkElementFactory of this Style.
                    UpdateChildChains( _childName, _childIndex,
                        treeNodeIsFE, treeNodeFO.FE, treeNodeFO.FCE,
                        affectedChildren, ref noChildIndexChildren );

                    // All FrameworkElementFactory-created elements point to the object
                    //  whose Style.VisualTree definition caused all this to occur
                    NewNodeStyledParentProperty( container, isContainerAnFE, treeNodeIsFE, treeNodeFO.FE, treeNodeFO.FCE );

                    // Initialize the per-instance data for the new element.  This
                    // needs to be done before any properties are invalidated.
                    if (_childIndex != -1)
                    {
                        Debug.Assert( _frameworkTemplate != null );

                        StyleHelper.CreateInstanceDataForChild(dataField, container, treeNode, _childIndex,
                            _frameworkTemplate.HasInstanceValues, ref _frameworkTemplate.ChildRecordFromChildIndex);
                    }

                    // If this element needs to know about the Loaded or Unloaded events, set the optimization
                    // bit in the element

                    if (HasLoadedChangeHandler)
                    {
                        BroadcastEventHelper.AddHasLoadedChangeHandlerFlagInAncestry(treeNode);
                    }
                }
                else
                {
                    if (_childName != null)
                    {
                        // Add this instance to the child index chain so that it may
                        // be tracked by the style

                        affectedChildren.Add(treeNode);
                    }
                    else
                    {
                        // Child nodes with no _childID (hence no _childIndex) are
                        //  tracked on a separate chain that will be appended to the
                        //  main chain for cleanup purposes.
                        if (noChildIndexChildren == null)
                        {
                            noChildIndexChildren = new List<DependencyObject>(4);
                        }

                        noChildIndexChildren.Add(treeNode);
                    }
                }


                // New node is initialized, build tree top down
                // (Node added before children of node)
                if (container == parent)
                {
                    // Set the NameScope on the root of the Template generated tree
                    TemplateNameScope templateNameScope = new TemplateNameScope(container);
                    NameScope.SetNameScope(treeNode, templateNameScope);

                    // This is the root of the tree
                    if (isContainerAnFE)
                    {
                        // The root is added to the Visual tree (not logical) for the
                        // case of FrameworkElement parents
                        containerAsFE.TemplateChild = treeNodeFO.FE;
                    }
                    else
                    {
                        // The root is added to the logical tree for the case
                        // of FrameworkContentElement parent.  This is the logical equivalent
                        // to what happens when adding a child to a visual collection.
                        AddNodeToLogicalTree( (FrameworkContentElement)parent, _type,
                            treeNodeIsFE, treeNodeFO.FE, treeNodeFO.FCE );
                    }
                }
                else
                {
                    // Call parent IAddChild to add treeNodeFO
                    AddNodeToParent( parent, treeNodeFO );
                }

                // Either set properties or invalidate them, depending on the type

                if (!treeNodeIsVisual3D)
                {
                    // For non-3D content, we need to invalidate any properties that
                    // came from FrameworkElementFactory.SetValue or VisulaTrigger.SetValue
                    // so that they can get picked up.

                    Debug.Assert( _frameworkTemplate != null );
                    StyleHelper.InvalidatePropertiesOnTemplateNode(
                                container,
                                treeNodeFO,
                                _childIndex,
                                ref _frameworkTemplate.ChildRecordFromChildIndex,
                                false /*isDetach*/,
                                this);

                }
                else
                {
                    // For 3D, which doesn't understand templates, we set the properties directly
                    // onto the newly-instantiated element.

                    for (int i = 0; i < PropertyValues.Count; i++)
                    {
                        if (PropertyValues[i].ValueType == PropertyValueType.Set)
                        {
                            // Get the value out of the table.
                            object o = PropertyValues[i].ValueInternal;


                            // If it's a freezable that can't be frozen, it's probably not sharable,
                            // so we make a copy of it.
                            Freezable freezableValue = o as Freezable;
                            if (freezableValue != null && !freezableValue.CanFreeze)
                            {
                                o = freezableValue.Clone();
                            }

                            // Or, if it's a markup extension, get the value
                            // to set on this property from the MarkupExtension itself.
                            MarkupExtension me = o as MarkupExtension;
                            if (me != null)
                            {
                                ProvideValueServiceProvider serviceProvider = new ProvideValueServiceProvider();
                                serviceProvider.SetData( treeNodeVisual3D, PropertyValues[i].Property );
                                o = me.ProvideValue( serviceProvider );
                            }

                            // Finally, set the value onto the object.
                            treeNodeVisual3D.SetValue(PropertyValues[i].Property, o);

                        }

                        else
                        {
                            // We don't support resource references, triggers, etc within the 3D content
                            throw new NotSupportedException(SR.Get(SRID.Template3DValueOnly, PropertyValues[i].Property) );

                        }

                    }
                }


                // Build child tree from factories
                FrameworkElementFactory childFactory = _firstChild;
                while (childFactory != null)
                {
                    childFactory.InstantiateTree(
                        dataField,
                        container,
                        treeNode,
                        affectedChildren,
                        ref noChildIndexChildren,
                        ref resourceDependents);

                    childFactory = childFactory._nextSibling;
                }

                if (!treeNodeIsVisual3D)
                {
                    // Fire "Initialized" event
                    NewNodeEndInit( treeNodeIsFE, treeNodeFO.FE, treeNodeFO.FCE );
                }
            }
            return treeNode;
        }
        // evaluate the current state of the trigger
        internal override bool GetCurrentState(DependencyObject container, UncommonField<HybridDictionary[]> dataField)
        {
            Debug.Assert( TriggerConditions != null && TriggerConditions.Length == 1,
                "This method assumes there is exactly one TriggerCondition." );

            return TriggerConditions[0].ConvertAndMatch(StyleHelper.GetDataTriggerValue(dataField, container, TriggerConditions[0].Binding));
        }
        //  ===========================================================================
        //  These methods are invoked when a Property
        //  value is fetched from a Style/Template
        //  ===========================================================================

        #region GetValueMethods

        //
        //  This method
        //  1. Computes the value of a template child
        //     (Index is '0' when the styled container is asking)
        //
        internal static object GetChildValue(
            UncommonField<HybridDictionary[]>   dataField,
            DependencyObject                    container,
            int                                 childIndex,
            FrameworkObject                     child,
            DependencyProperty                  dp,
            ref FrugalStructList<ChildRecord>   childRecordFromChildIndex,
            ref EffectiveValueEntry             entry,
            out ValueLookupType                 sourceType,
            FrameworkElementFactory             templateRoot)
        {
            object value = DependencyProperty.UnsetValue;
            sourceType = ValueLookupType.Simple;

            // Check if this Child Index is represented in given data-structure
            if ((0 <= childIndex) && (childIndex < childRecordFromChildIndex.Count))
            {
                // Fetch the childRecord for the given childIndex
                ChildRecord childRecord = childRecordFromChildIndex[childIndex];

                // Check if this Property is represented in the childRecord
                int mapIndex = childRecord.ValueLookupListFromProperty.Search(dp.GlobalIndex);
                if (mapIndex >= 0)
                {
                    if (childRecord.ValueLookupListFromProperty.Entries[mapIndex].Value.Count > 0)
                    {
                        // Child Index/Property are both represented in this style/template,
                        // continue with value computation

                        // Pass into helper so ValueLookup struct can be accessed by ref
                        value = GetChildValueHelper(
                            dataField,
                            ref childRecord.ValueLookupListFromProperty.Entries[mapIndex].Value,
                            dp,
                            container,
                            child,
                            childIndex,
                            true,
                            ref entry,
                            out sourceType,
                            templateRoot);
                    }
                }
            }

            return value;
        }
        //+----------------------------------------------------------------------------------
        //
        //  ApplyTemplateContent
        //
        //  Instantiate the content of the template (either from FEFs or from Baml).
        //  This is done for every element to which this template is attached.
        //
        //+----------------------------------------------------------------------------------
        #region InstantiateSubTree

        //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647
        internal static bool ApplyTemplateContent(
            UncommonField<HybridDictionary[]>  dataField,
            DependencyObject            container,
            FrameworkElementFactory     templateRoot,
            int                         lastChildIndex,
            HybridDictionary            childIndexFromChildID,
            FrameworkTemplate           frameworkTemplate)
        {
            Debug.Assert(frameworkTemplate != null );

            bool visualsCreated = false;

            FrameworkElement feContainer = container as FrameworkElement;

            // Is this a FEF-style template?

            if (templateRoot != null)
            {
                // Yes, we'll instantiate from a FEF tree.

                EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose, EventTrace.Event.WClientParseInstVisTreeBegin);

                CheckForCircularReferencesInTemplateTree(container, frameworkTemplate );

                // Container is considered ChildIndex '0' (Self), but,
                // Container.ChildIndex isn't set
                List<DependencyObject> affectedChildren = new List<DependencyObject>(lastChildIndex);

                // Assign affectedChildren to container
                TemplatedFeChildrenField.SetValue(container, affectedChildren);

                // When building the template children chain, we keep a chain of
                // nodes that don't need to be in the chain for property invalidation
                // or lookup purposes.  (And hence not assigned a TemplateChildIndex)
                // We only need them in order to clean up their _templatedParent
                // references (see FrameworkElement.ClearTemplateChain)
                List<DependencyObject> noChildIndexChildren = null;

                // Instantiate template
                // Setup container's reference to first child in chain
                // and add to tree
                DependencyObject treeRoot = templateRoot.InstantiateTree(
                    dataField,
                    container,
                    container,
                    affectedChildren,
                    ref noChildIndexChildren,
                    ref frameworkTemplate.ResourceDependents);

                Debug.Assert(treeRoot is FrameworkElement || treeRoot is FrameworkContentElement,
                    "Root node of tree must be a FrameworkElement or FrameworkContentElement.  This should have been caught by set_VisualTree" );

                // From childFirst to childLast is the chain of child nodes with
                //  childIndex.  Append that chain with the chain of child nodes
                //  with no childIndex assigned.
                if( noChildIndexChildren != null )
                {
                    affectedChildren.AddRange(noChildIndexChildren);
                }

                visualsCreated = true;

                if (feContainer != null && EventTrace.IsEnabled(EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose))
                {
                    string label = feContainer.Name;
                    if (label == null || label.Length == 0)
                        label = container.GetHashCode().ToString(System.Globalization.CultureInfo.InvariantCulture);

                    EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientParseInstVisTreeEnd, EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose,
                                                         String.Format(System.Globalization.CultureInfo.InvariantCulture, "Style.InstantiateSubTree for {0} {1}", container.GetType().Name, label));
                }
            }

            // It's not a FEF-style template, is it a non-empty optimized one?

            else if (frameworkTemplate != null && frameworkTemplate.HasXamlNodeContent)
            {
                // Yes, create from the optimized template content.
                EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose, EventTrace.Event.WClientParseInstVisTreeBegin);

                CheckForCircularReferencesInTemplateTree(container, frameworkTemplate );

                // Container is considered ChildIndex '0' (Self), but,
                // Container.ChildIndex isn't set

                List<DependencyObject> affectedChildren = new List<DependencyObject>(lastChildIndex);

                // Assign affectedChildren to container

                TemplatedFeChildrenField.SetValue(container, affectedChildren);

                DependencyObject treeRoot;

                // Load the content

                treeRoot = frameworkTemplate.LoadContent( container, affectedChildren);

                Debug.Assert(treeRoot == null || treeRoot is FrameworkElement || treeRoot is FrameworkContentElement,
                    "Root node of tree must be a FrameworkElement or FrameworkContentElement.  This should have been caught by set_VisualTree" );

                visualsCreated = true;

                if (feContainer != null && EventTrace.IsEnabled(EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose))
                {
                    string label = feContainer.Name;
                    if (label == null || label.Length == 0)
                        label = container.GetHashCode().ToString(System.Globalization.CultureInfo.InvariantCulture);

                    EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientParseInstVisTreeEnd, EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose,
                                                         String.Format(System.Globalization.CultureInfo.InvariantCulture, "Style.InstantiateSubTree for {0} {1}", container.GetType().Name, label));
                }
            }

            // No template was supplied.  Allow subclasses to provide the template.
            // This is currently only implemented for FrameworkElement's.

            else
            {
                if (feContainer != null)
                {
                    // This template will not be driven by the Style in any way.
                    // Rather, it will be built and initialized by the callee

                    // CALLBACK
#if DEBUG
                    Debug.Assert( feContainer._buildVisualTreeVerification == VerificationState.WaitingForBuildVisualTree,
                        "The BuildVisualTree override has triggered another call to itself.  This is not good - something between the two Style.InstantiateSubTree calls on the stack is doing A Very Bad Thing.");
                    feContainer._buildVisualTreeVerification = VerificationState.WaitingForAddCustomTemplateRoot;
                    bool exceptionThrown = true;
                    try
                    {
#endif

                    Debug.Assert(frameworkTemplate != null, "Only FrameworkTemplate has the ability to build a VisualTree by this means");
                    visualsCreated = frameworkTemplate.BuildVisualTree(feContainer);

#if DEBUG
                    exceptionThrown = false;
                    }
                    finally
                    {
                        if (!exceptionThrown)   // results are unreliable if an exception was thrown
                        {
                            if( visualsCreated )
                            {
                                Debug.Assert( feContainer._buildVisualTreeVerification == VerificationState.WaitingForBuildVisualTreeCompletion,
                                    "A derived class overriding BuildVisualTree must call AddCustomTemplateRoot to attach its custom subtree before exiting.");
                            }
                            else
                            {
                                Debug.Assert( feContainer._buildVisualTreeVerification == VerificationState.WaitingForAddCustomTemplateRoot,
                                    "If a derived class overriding BuildVisualTree has called AddCustomTemplateRoot to attach its custom subtree, its BuildVisualTree must return true to indicate that it has done so.");
                            }
                        }

                        // All done building this visual tree, stand by for the next one.
                        feContainer._buildVisualTreeVerification = VerificationState.WaitingForBuildVisualTree;
                    }
#endif
                }
            }

            return visualsCreated;
        }
        //
        //  This method
        //  1. Is called when a style/template is removed from a container.
        //  2. It is meant to release its data trigger information.
        //
        private static void ReleaseInstanceDataForDataTriggers(
            UncommonField<HybridDictionary[]> dataField,
            HybridDictionary            instanceValues,
            Style                       oldStyle,
            FrameworkTemplate           oldFrameworkTemplate)
        {
            Debug.Assert(oldStyle != null || oldFrameworkTemplate != null );

            if (instanceValues == null)
                return;

            // the event handler depends only on whether the instance data
            // applies to Style, Template, or ThemeStyle
            EventHandler<BindingValueChangedEventArgs> handler;
            if (dataField == StyleDataField)
            {
                handler = new EventHandler<BindingValueChangedEventArgs>(OnBindingValueInStyleChanged);
            }
            else if (dataField == TemplateDataField)
            {
                handler = new EventHandler<BindingValueChangedEventArgs>(OnBindingValueInTemplateChanged);
            }
            else
            {
                Debug.Assert(dataField == ThemeStyleDataField);
                handler = new EventHandler<BindingValueChangedEventArgs>(OnBindingValueInThemeStyleChanged);
            }

            // clean up triggers with setters
            HybridDictionary dataTriggerRecordFromBinding = null;
            if (oldStyle != null)
            {
                dataTriggerRecordFromBinding = oldStyle._dataTriggerRecordFromBinding;
            }
            else if (oldFrameworkTemplate != null)
            {
                dataTriggerRecordFromBinding = oldFrameworkTemplate._dataTriggerRecordFromBinding;
            }

            if (dataTriggerRecordFromBinding != null)
            {
                foreach (object o in dataTriggerRecordFromBinding.Keys)
                {
                    BindingBase binding = (BindingBase)o;
                    ReleaseInstanceDataForTriggerBinding(binding, instanceValues, handler);
                }
            }

            // clean up triggers with actions
            HybridDictionary dataTriggersWithActions = null;
            if (oldStyle != null)
            {
                dataTriggersWithActions = oldStyle.DataTriggersWithActions;
            }
            else if (oldFrameworkTemplate != null)
            {
                dataTriggersWithActions = oldFrameworkTemplate.DataTriggersWithActions;
            }

            if (dataTriggersWithActions != null)
            {
                foreach (object o in dataTriggersWithActions.Keys)
                {
                    BindingBase binding = (BindingBase)o;
                    ReleaseInstanceDataForTriggerBinding(binding, instanceValues, handler);
                }
            }
        }
        //
        //  This method
        //  1. Ensures that the desired per-instance storage
        //     for Style/Template exists
        //  2. Also allows you to specify initial capacity
        //
        internal static HybridDictionary EnsureInstanceData(
            UncommonField<HybridDictionary[]>  dataField,
            DependencyObject            container,
            InstanceStyleData           dataType,
            int                         initialSize)
        {
            Debug.Assert((container is FrameworkElement) || (container is FrameworkContentElement), "Caller has queried with non-framework element.  Bad caller, bad!");
            Debug.Assert(dataType < InstanceStyleData.ArraySize, "Caller has queried using a value outside the range of the Enum.  Bad caller, bad!");

            HybridDictionary[] data = dataField.GetValue(container);

            if (data == null)
            {
                data = new HybridDictionary[(int)InstanceStyleData.ArraySize];
                dataField.SetValue(container, data);
            }

            if (data[(int)dataType] == null )
            {
                if( initialSize < 0 )
                {
                    data[(int)dataType] = new HybridDictionary();
                }
                else
                {
                    data[(int)dataType] = new HybridDictionary(initialSize);
                }
            }

            return (HybridDictionary)data[(int)dataType];
        }
 //
 //  This method
 //  1. Ensures that the desired per-instance storage
 //     for Style/Template exists
 //
 internal static HybridDictionary EnsureInstanceData(
     UncommonField<HybridDictionary[]>  dataField,
     DependencyObject            container,
     InstanceStyleData           dataType)
 {
     return EnsureInstanceData(dataField, container, dataType, -1);
 }
        //
        //  This method
        //  1. Is called whenever a new Style/Template is upapplied from an FE/FCE
        //  2. It removes per-instance StyleData/TemplateData for the old Style/Template
        //
        internal static void ReleaseInstanceData(
            UncommonField<HybridDictionary[]>  dataField,
            DependencyObject            container,
            FrameworkElement            fe,
            FrameworkContentElement     fce,
            Style                       oldStyle,
            FrameworkTemplate           oldFrameworkTemplate,
            InternalFlags               hasGeneratedSubTreeFlag)
        {
            Debug.Assert((fe != null && fce == null) || (fe == null && fce != null));
            Debug.Assert((fe != null && fe == container) || (fce != null && fce == container));
            Debug.Assert(oldStyle != null || oldFrameworkTemplate != null );

            // Fetch the per-instance data field value
            HybridDictionary[] styleData = dataField.GetValue(container);

            if (oldStyle != null)
            {
                HybridDictionary instanceValues = (styleData != null) ? styleData[(int)InstanceStyleData.InstanceValues] : null;
                ReleaseInstanceDataForDataTriggers(dataField, instanceValues, oldStyle, oldFrameworkTemplate );
                if (oldStyle.HasInstanceValues)
                {
                    StyleHelper.ProcessInstanceValuesForChild(
                        container, container, 0, instanceValues, false,
                        ref oldStyle.ChildRecordFromChildIndex);
                }
            }
            else if (oldFrameworkTemplate != null)
            {
                HybridDictionary instanceValues = (styleData != null) ? styleData[(int)InstanceStyleData.InstanceValues] : null;
                ReleaseInstanceDataForDataTriggers(dataField, instanceValues, oldStyle, oldFrameworkTemplate );
                if (oldFrameworkTemplate.HasInstanceValues)
                {
                    StyleHelper.ProcessInstanceValuesForChild(
                        container, container, 0, instanceValues, false,
                        ref oldFrameworkTemplate.ChildRecordFromChildIndex);
                }
            }
            else
            {
                HybridDictionary instanceValues = (styleData != null) ? styleData[(int)InstanceStyleData.InstanceValues] : null;
                ReleaseInstanceDataForDataTriggers(dataField, instanceValues, oldStyle, oldFrameworkTemplate );
            }
        }
 //
 //  This method
 //  1. Adds the new TemplateNode's information to the container's per-instance
 //     StyleData/TemplateData. (This only makes sense for children created via
 //     FrameworkElementFactory. Children acquired via BuildVisualTree don't use
 //     any property-related funtionality of the Style/Template.)
 //
 internal static void CreateInstanceDataForChild(
     UncommonField<HybridDictionary[]>   dataField,
     DependencyObject                    container,
     DependencyObject                    child,
     int                                 childIndex,
     bool                                hasInstanceValues,
     ref FrugalStructList<ChildRecord>   childRecordFromChildIndex)
 {
     if (hasInstanceValues)
     {
         HybridDictionary instanceValues = EnsureInstanceData(dataField, container, InstanceStyleData.InstanceValues);
         StyleHelper.ProcessInstanceValuesForChild(
             container, child, childIndex, instanceValues, true,
             ref childRecordFromChildIndex);
     }
 }
        //
        //  This method
        //  1. Computes the property value given the ChildLookupValue list for it
        //
        private static object GetChildValueHelper(
            UncommonField<HybridDictionary[]>       dataField,
            ref ItemStructList<ChildValueLookup>    valueLookupList,
            DependencyProperty                      dp,
            DependencyObject                        container,
            FrameworkObject                         child,
            int                                     childIndex,
            bool                                    styleLookup,
            ref EffectiveValueEntry                 entry,
            out ValueLookupType                     sourceType,
            FrameworkElementFactory                 templateRoot)
        {
            Debug.Assert(child.IsValid, "child should either be an FE or an FCE");

            object value = DependencyProperty.UnsetValue;
            sourceType = ValueLookupType.Simple;

            // Walk list backwards since highest priority lookup items are inserted last
            for (int i = valueLookupList.Count - 1; i >= 0; i--)
            {
                sourceType = valueLookupList.List[i].LookupType;

                // Lookup logic is determined by lookup type. "Trigger"
                // is misleading right now because today it's also being used
                // for Storyboard timeline lookups.
                switch (valueLookupList.List[i].LookupType)
                {
                case ValueLookupType.Simple:
                    {
                        // Simple value
                        value = valueLookupList.List[i].Value;
                    }
                    break;

                case ValueLookupType.Trigger:
                case ValueLookupType.PropertyTriggerResource:
                case ValueLookupType.DataTrigger:
                case ValueLookupType.DataTriggerResource:
                    {
                        // Conditional value based on Container state
                        bool triggerMatch = true;

                        if( valueLookupList.List[i].Conditions != null )
                        {
                            // Check whether the trigger applies.  All conditions must match,
                            // so the loop can terminate as soon as it finds a condition
                            // that doesn't match.
                            for (int j = 0; triggerMatch && j < valueLookupList.List[i].Conditions.Length; j++)
                            {
                                object state;

                                switch (valueLookupList.List[i].LookupType)
                                {
                                case ValueLookupType.Trigger:
                                case ValueLookupType.PropertyTriggerResource:
                                    // Find the source node
                                    DependencyObject sourceNode;
                                    int sourceChildIndex = valueLookupList.List[i].Conditions[j].SourceChildIndex;
                                    if (sourceChildIndex == 0)
                                    {
                                        sourceNode = container;
                                    }
                                    else
                                    {
                                        sourceNode = StyleHelper.GetChild(container, sourceChildIndex);
                                    }

                                    // Note that the sourceNode could be null when the source
                                    // property for this trigger is on a node that hasn't been
                                    // instantiated yet.
                                    DependencyProperty sourceProperty = valueLookupList.List[i].Conditions[j].Property;
                                    if (sourceNode != null)
                                    {
                                        state = sourceNode.GetValue(sourceProperty);
                                    }
                                    else
                                    {
                                        Type sourceNodeType;

                                        if( templateRoot != null )
                                        {
                                            sourceNodeType = FindFEF(templateRoot, sourceChildIndex).Type;
                                        }
                                        else
                                        {
                                            sourceNodeType = (container as FrameworkElement).TemplateInternal.ChildTypeFromChildIndex[sourceChildIndex];
                                        }

                                        state = sourceProperty.GetDefaultValue(sourceNodeType);
                                    }

                                    triggerMatch = valueLookupList.List[i].Conditions[j].Match(state);

                                    break;

                                case ValueLookupType.DataTrigger:
                                case ValueLookupType.DataTriggerResource:
                                default:    // this cannot happen - but make the compiler happy

                                    state = GetDataTriggerValue(dataField, container, valueLookupList.List[i].Conditions[j].Binding);
                                    triggerMatch = valueLookupList.List[i].Conditions[j].ConvertAndMatch(state);

                                    break;
                                }
                            }
                        }

                        if (triggerMatch)
                        {
                            // Conditionals matched, use the value

                            if (valueLookupList.List[i].LookupType == ValueLookupType.PropertyTriggerResource ||
                                valueLookupList.List[i].LookupType == ValueLookupType.DataTriggerResource)
                            {
                                // Resource lookup
                                object source;
                                value = FrameworkElement.FindResourceInternal(child.FE,
                                                                              child.FCE,
                                                                              dp,
                                                                              valueLookupList.List[i].Value,  // resourceKey
                                                                              null,  // unlinkedParent
                                                                              true,  // allowDeferredResourceReference
                                                                              false, // mustReturnDeferredResourceReference
                                                                              null,  // boundaryElement
                                                                              false, // disableThrowOnResourceNotFound
                                                                              out source);

                                // Try to freeze the value
                                SealIfSealable(value);
                            }
                            else
                            {
                                value = valueLookupList.List[i].Value;
                            }
                        }
                    }
                    break;

                case ValueLookupType.TemplateBinding:
                    {
                        TemplateBindingExtension templateBinding = (TemplateBindingExtension)valueLookupList.List[i].Value;
                        DependencyProperty sourceProperty = templateBinding.Property;

                        // Direct binding of Child property to Container
                        value = container.GetValue(sourceProperty);

                        // Apply the converter, if any
                        if (templateBinding.Converter != null)
                        {
                            DependencyProperty targetProperty = valueLookupList.List[i].Property;
                            System.Globalization.CultureInfo culture = child.Language.GetCompatibleCulture();

                            value = templateBinding.Converter.Convert(
                                                value,
                                                targetProperty.PropertyType,
                                                templateBinding.ConverterParameter,
                                                culture);
                        }

                        // if the binding returns an invalid value, fallback to default value
                        if ((value != DependencyProperty.UnsetValue) && !dp.IsValidValue(value))
                        {
                            value = DependencyProperty.UnsetValue;
                        }
                    }
                    break;

                case ValueLookupType.Resource:
                    {
                        // Resource lookup
                        object source;
                        value = FrameworkElement.FindResourceInternal(
                                        child.FE,
                                        child.FCE,
                                        dp,
                                        valueLookupList.List[i].Value,  // resourceKey
                                        null,  // unlinkedParent
                                        true,  // allowDeferredResourceReference
                                        false, // mustReturnDeferredResourceReference
                                        null,  // boundaryElement
                                        false, // disableThrowOnResourceNotFound
                                        out source);

                        // Try to freeze the value
                        SealIfSealable(value);
                    }
                    break;
                }

                // See if value needs per-instance storage
                if (value != DependencyProperty.UnsetValue)
                {
                    entry.Value = value;
                    // When the value requires per-instance storage (and comes from this style),
                    // get the real value from per-instance data.
                    switch (valueLookupList.List[i].LookupType)
                    {
                    case ValueLookupType.Simple:
                    case ValueLookupType.Trigger:
                    case ValueLookupType.DataTrigger:
                        {
                            MarkupExtension me;
                            Freezable freezable;

                            if ((me = value as MarkupExtension) != null)
                            {
                                value = GetInstanceValue(
                                                dataField,
                                                container,
                                                child.FE,
                                                child.FCE,
                                                childIndex,
                                                valueLookupList.List[i].Property,
                                                i,
                                                ref entry);
                            }
                            else if ((freezable = value as Freezable) != null && !freezable.IsFrozen)
                            {
                                value = GetInstanceValue(
                                                dataField,
                                                container,
                                                child.FE,
                                                child.FCE,
                                                childIndex,
                                                valueLookupList.List[i].Property,
                                                i,
                                                ref entry);
                            }
                        }
                        break;

                    default:
                        break;
                    }
                }

                if (value != DependencyProperty.UnsetValue)
                {
                    // Found a value, break out of the for() loop.
                    break;
                }
            }

            return value;
        }
        // Given a Style/Template and a Binding whose value has changed, look for
        //  any data triggers that have trigger actions (EnterAction/ExitAction)
        //  and see if any of those actions need to run as a response to this change.
        private static void InvokeApplicableDataTriggerActions(
            Style                               style,
            FrameworkTemplate                   frameworkTemplate,
            DependencyObject                    container,
            BindingBase                         binding,
            BindingValueChangedEventArgs        e,
            UncommonField<HybridDictionary[]>   dataField)
        {
            HybridDictionary dataTriggersWithActions;

            if( style != null )
            {
                dataTriggersWithActions = style.DataTriggersWithActions;
            }
            else if( frameworkTemplate != null )
            {
                dataTriggersWithActions = frameworkTemplate.DataTriggersWithActions;
            }
            else
            {
                dataTriggersWithActions = null;
            }

            if( dataTriggersWithActions != null )
            {
                object candidateTrigger = dataTriggersWithActions[binding];

                if( candidateTrigger != null )
                {
                    // One or more trigger objects need to be evaluated.  The candidateTrigger
                    //  object may be a single trigger or a collection of them.
                    TriggerBase triggerBase = candidateTrigger as TriggerBase;
                    if( triggerBase != null )
                    {
                        InvokeDataTriggerActions( triggerBase, container, binding, e,
                            style, frameworkTemplate, dataField);
                    }
                    else
                    {
                        Debug.Assert(candidateTrigger is List<TriggerBase>, "Internal data structure error: The HybridDictionary [Style/Template].DataTriggersWithActions " +
                            "is expected to hold a single TriggerBase or a List<T> of them.  An object of type " +
                            candidateTrigger.GetType().ToString() + " is not expected.  Where did this object come from?");

                        List<TriggerBase> triggerList = (List<TriggerBase>)candidateTrigger;

                        for( int i = 0; i < triggerList.Count; i++ )
                        {
                            InvokeDataTriggerActions( triggerList[i], container, binding, e,
                                style, frameworkTemplate, dataField);
                        }
                    }
                }
            }
        }
        //
        //  This method
        //  1. Retrieves a value from a binding in the condition of a data trigger
        //
        internal static object GetDataTriggerValue(
            UncommonField<HybridDictionary[]>  dataField,
            DependencyObject            container,
            BindingBase                 binding)
        {
            // get the container's instance value list - the bindings are stored there
            HybridDictionary[] data = dataField.GetValue(container);
            HybridDictionary instanceValues = EnsureInstanceData(dataField, container, InstanceStyleData.InstanceValues);

            // get the binding, creating it if necessary
            BindingExpressionBase bindingExpr = (BindingExpressionBase)instanceValues[binding];
            if (bindingExpr == null)
            {
                bindingExpr = BindingExpression.CreateUntargetedBindingExpression(container, binding);
                instanceValues[binding] = bindingExpr;

                if (dataField == StyleDataField)
                {
                    bindingExpr.ValueChanged += new EventHandler<BindingValueChangedEventArgs>(OnBindingValueInStyleChanged);
                }
                else if (dataField == TemplateDataField)
                {
                    bindingExpr.ResolveNamesInTemplate = true;
                    bindingExpr.ValueChanged += new EventHandler<BindingValueChangedEventArgs>(OnBindingValueInTemplateChanged);
                }
                else
                {
                    Debug.Assert(dataField == ThemeStyleDataField);
                    bindingExpr.ValueChanged += new EventHandler<BindingValueChangedEventArgs>(OnBindingValueInThemeStyleChanged);
                }
                bindingExpr.Attach(container);
            }

            // get the value
            return bindingExpr.Value;
        }
Example #19
0
        // evaluate the current state of the trigger 
        internal override bool GetCurrentState(DependencyObject container, UncommonField<HybridDictionary[]> dataField)
        {
            Debug.Assert( TriggerConditions != null && TriggerConditions.Length == 1,
                "This method assumes there is exactly one TriggerCondition." ); 

            Debug.Assert( TriggerConditions[0].SourceChildIndex == 0, 
                "This method was created to handle properties on the containing object, more work is needed to handle templated children too." ); 

            return TriggerConditions[0].Match(container.GetValue(TriggerConditions[0].Property)); 
        }
        //
        //  This method
        //  1. Retrieves an instance value from per-instance StyleData.
        //  2. Creates the StyleData if this is the first request.
        //
        internal static object GetInstanceValue(
            UncommonField<HybridDictionary []>  dataField,
            DependencyObject            container,
            FrameworkElement            feChild,
            FrameworkContentElement     fceChild,
            int                         childIndex,
            DependencyProperty          dp,
            int                         i,
            ref EffectiveValueEntry     entry)
        {
            object rawValue = entry.Value;
            DependencyObject child = null;

            FrameworkElement feContainer;
            FrameworkContentElement fceContainer;
            Helper.DowncastToFEorFCE(container, out feContainer, out fceContainer, true);

            HybridDictionary[] styleData = (dataField != null) ? dataField.GetValue(container) : null;
            HybridDictionary instanceValues = (styleData != null) ? styleData[(int)InstanceStyleData.InstanceValues] : null;
            InstanceValueKey key = new InstanceValueKey(childIndex, dp.GlobalIndex, i);

            object value = (instanceValues != null)? instanceValues[key] : null;
            bool isRequestingExpression = (feChild != null) ? feChild.IsRequestingExpression : fceChild.IsRequestingExpression;

            if (value == null)
            {
                value = NotYetApplied;
            }

            // if the value is a detached expression, replace it with a new one
            Expression expr = value as Expression;
            if (expr != null && expr.HasBeenDetached)
            {
                value = NotYetApplied;
            }

            // if this is the first request, create the value
            if (value == NotYetApplied)
            {
                child = feChild;
                if (child == null)
                    child = fceChild;

                MarkupExtension me;
                Freezable freezable;

                if ((me = rawValue as MarkupExtension) != null)
                {
                    // exception:  if the child is not yet initialized and the request
                    // is for an expression, don't create the value.  This gives the parser
                    // a chance to set local values, to override the style-defined values.
                    if (isRequestingExpression)
                    {
                        bool isInitialized = (feChild != null) ? feChild.IsInitialized : fceChild.IsInitialized;
                        if (!isInitialized)
                        {
                            return DependencyProperty.UnsetValue;
                        }
                    }

                    ProvideValueServiceProvider provideValueServiceProvider = new ProvideValueServiceProvider();
                    provideValueServiceProvider.SetData( child, dp );
                    value = me.ProvideValue(provideValueServiceProvider);
                }
                else if ((freezable = rawValue as Freezable) != null)
                {
                    value = freezable.Clone();
                    child.ProvideSelfAsInheritanceContext(value, dp);
                }

                // store it in per-instance StyleData (even if it's DependencyProperty.UnsetValue)
                Debug.Assert(value != NotYetApplied, "attempt to retrieve instance value that was never set");
                instanceValues[key] = value;

                if (value != DependencyProperty.UnsetValue)
                {
                    expr = value as Expression;
                    // if the instance value is an expression, attach it
                    if (expr != null)
                    {
                        expr.OnAttach(child, dp);
                    }
                }
            }

            // if the value is an Expression (and we're being asked for the real value),
            // delegate to the expression.
            if (expr != null)
            {
                if (!isRequestingExpression)
                {
                    if (child == null)
                    {
                        child = feChild;
                        if (child == null)
                            child = fceChild;
                    }

                    entry.ResetValue(DependencyObject.ExpressionInAlternativeStore, true);
                    entry.SetExpressionValue(expr.GetValue(child, dp), DependencyObject.ExpressionInAlternativeStore);
                }
                else
                {
                    entry.Value = value;
                }
            }
            else
            {
                entry.Value = value;
            }

            return value;
        }
Example #21
0
        //  ===========================================================================
        //  These methods are invoked to during a call call to
        //  FE.EnsureVisual or FCE.EnsureLogical
        //  ===========================================================================

        #region InstantiateSubTree

        //
        //  This method
        //  Creates the VisualTree
        //
        //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647
        internal bool ApplyTemplateContent(
            UncommonField<HybridDictionary[]> templateDataField,
            FrameworkElement container)
        {
#if STYLE_TRACE
            _timer.Begin();
#endif

            if (TraceDependencyProperty.IsEnabled)
            {
                TraceDependencyProperty.Trace(
                    TraceEventType.Start,
                    TraceDependencyProperty.ApplyTemplateContent,
                    container,
                    this);
            }


            ValidateTemplatedParent(container);

            bool visualsCreated = StyleHelper.ApplyTemplateContent(templateDataField, container,
                _templateRoot, _lastChildIndex,
                ChildIndexFromChildName, this);

            if (TraceDependencyProperty.IsEnabled)
            {
                TraceDependencyProperty.Trace(
                    TraceEventType.Stop,
                    TraceDependencyProperty.ApplyTemplateContent,
                    container,
                    this);
            }


#if STYLE_TRACE
            _timer.End();
            if (visualsCreated)
            {
                string label = container.ID;
                if (label == null || label.Length == 0)
                    label = container.GetHashCode().ToString();
                Console.WriteLine("  Style.VT created for {0} {1} in {2:f2} msec",
                    container.GetType().Name, label, _timer.TimeOfLastPeriod);
            }
#endif

            return visualsCreated;
        }
        // This is expected to be called when a Binding for a DataTrigger has
        //   changed and we need to look for true/false transitions.  If found,
        //   invoke EnterAction (or ExitAction) as needed.
        private static void InvokeDataTriggerActions( TriggerBase triggerBase,
            DependencyObject triggerContainer, BindingBase binding, BindingValueChangedEventArgs bindingChangedArgs,
            Style style, FrameworkTemplate frameworkTemplate,
            UncommonField<HybridDictionary[]> dataField)
        {
            bool oldState;
            bool newState;

            DataTrigger dataTrigger = triggerBase as DataTrigger;

            if( dataTrigger != null )
            {
                EvaluateOldNewStates( dataTrigger, triggerContainer,
                    binding, bindingChangedArgs, dataField,
                    style, frameworkTemplate,
                    out oldState, out newState );
            }
            else
            {
                Debug.Assert( triggerBase is MultiDataTrigger,
                    "This method only handles DataTrigger and MultiDataTrigger.  Other types should have been handled elsewhere." );

                EvaluateOldNewStates( (MultiDataTrigger)triggerBase, triggerContainer,
                    binding, bindingChangedArgs, dataField,
                    style, frameworkTemplate,
                    out oldState, out newState );
            }

            InvokeEnterOrExitActions( triggerBase, oldState, newState, triggerContainer,
                style, frameworkTemplate  );
        }
Example #23
0
        // evaluate the current state of the trigger
        internal virtual bool GetCurrentState(DependencyObject container, UncommonField<HybridDictionary[]> dataField)
        {
            Debug.Assert( false,
                "This method was written to handle Trigger, MultiTrigger, DataTrigger, and MultiDataTrigger.  It looks like a new trigger type was added - please add support as appropriate.");

            return false;
        }
        // Called from UpdateStyleCache - When an object's Style changes, some of
        //  the triggers contain EnterActions and they want to be run immediately
        //  if the trigger condition evaluates to true.
        // Usually these EnterActions are to be run when there's a False->True
        //  transition.  This code treats "true at time Style is applied" as
        //  a False->True transition even though it's possible no transition ever
        //  took place.
        private static void ExecuteOnApplyEnterExitActions( FrameworkElement fe,
            FrameworkContentElement fce, Style style, UncommonField<HybridDictionary[]> dataField )
        {
            // If the "Style Change" is the style being set to null - exit.
            if( style == null )
            {
                return;
            }
            // Note: PropertyTriggersWithActions is a FrugalMap, so its count is checked against zero.
            //  DataTriggersWithActions is a HybridDictionary allocated on demand, so it's checked against null.
            if( style.PropertyTriggersWithActions.Count == 0 && style.DataTriggersWithActions == null )
            {
                // Style has no trigger actions at all, exit.
                return;
            }

            TriggerCollection triggers = style.Triggers;
            DependencyObject triggerContainer = (fe != null) ? (DependencyObject)fe : (DependencyObject)fce;

            ExecuteOnApplyEnterExitActionsLoop( triggerContainer, triggers, style, null, dataField );
        }
Example #25
0
        // evaluate the current state of the trigger
        internal override bool GetCurrentState(DependencyObject container, UncommonField<HybridDictionary[]> dataField)
        {
            bool retVal = (TriggerConditions.Length > 0);

            for( int i = 0; retVal && i < TriggerConditions.Length; i++ )
            {
                retVal = TriggerConditions[i].ConvertAndMatch(StyleHelper.GetDataTriggerValue(dataField, container, TriggerConditions[i].Binding));
            }

            return retVal;
        }
        //  ===========================================================================
        //  These methods are invoked when a visual tree is
        //  being created/destroyed via a Style/Template and
        //  when a Style/Template is being applied or
        //  unapplied to a FE/FCE
        //  ===========================================================================

        #region WriteInstanceData

        //
        //  This method
        //  1. Is called whenever a Style/Template is [un]applied to an FE/FCE
        //  2. It updates the per-instance StyleData/TemplateData
        //
        internal static void UpdateInstanceData(
            UncommonField<HybridDictionary[]> dataField,
            FrameworkElement           fe,
            FrameworkContentElement    fce,
            Style                      oldStyle,
            Style                      newStyle,
            FrameworkTemplate          oldFrameworkTemplate,
            FrameworkTemplate          newFrameworkTemplate,
            InternalFlags              hasGeneratedSubTreeFlag)
        {
            Debug.Assert((fe != null && fce == null) || (fe == null && fce != null));

            DependencyObject container = (fe != null) ? (DependencyObject)fe : (DependencyObject)fce;

            if (oldStyle != null || oldFrameworkTemplate != null )
            {
                ReleaseInstanceData(dataField, container, fe, fce, oldStyle, oldFrameworkTemplate, hasGeneratedSubTreeFlag);
            }

            if (newStyle != null || newFrameworkTemplate != null )
            {
                CreateInstanceData(dataField, container, fe, fce, newStyle, newFrameworkTemplate );
            }
            else
            {
                dataField.ClearValue(container);
            }
        }