// // This method // 1. Is invoked when the TemplateProperty is invalidated on a Control, // Page, PageFunctionBase, ContentPresenter, or a sub-class thereof. // internal static void DoTemplateInvalidations( FrameworkElement feContainer, FrameworkTemplate oldFrameworkTemplate) { Debug.Assert(feContainer != null); DependencyObject container; HybridDictionary[] oldTemplateData; FrameworkTemplate newFrameworkTemplate = null; object oldTemplate; object newTemplate; bool newTemplateHasResourceReferences; Debug.Assert(feContainer != null); // Fetch the per-instance data before it goes away (during Template_get) oldTemplateData = StyleHelper.TemplateDataField.GetValue(feContainer); // Do immediate pull of Template to refresh the value since the // new Template needs to be known at this time to do accurate // invalidations newFrameworkTemplate = feContainer.TemplateInternal; container = feContainer; oldTemplate = oldFrameworkTemplate; newTemplate = newFrameworkTemplate; newTemplateHasResourceReferences = (newFrameworkTemplate != null) ? newFrameworkTemplate.HasResourceReferences : false; // If the template wants to watch for the Loaded and/or Unloaded events, set the // flag that says we want to receive it. Otherwise, if it was set in the old template, clear it. StyleHelper.UpdateLoadedFlag( container, oldFrameworkTemplate, newFrameworkTemplate ); if (oldTemplate != newTemplate) { // // Template is changing // // Set up any per-instance state relating to the new Template // We do this here instead of OnTemplateInvalidated because // this needs to happen for the *first* Template. StyleHelper.UpdateInstanceData( StyleHelper.TemplateDataField, feContainer /* fe */, null /* fce */, null /*oldStyle */, null /* newStyle */, oldFrameworkTemplate, newFrameworkTemplate, InternalFlags.HasTemplateGeneratedSubTree); // If this new template has resource references (either for the container // or for children in the visual tree), then, mark it so that it will // not be ignored during resource change invalidations if (newTemplate != null && newTemplateHasResourceReferences) { Debug.Assert(feContainer != null); feContainer.HasResourceReference = true; } // If the template wants to watch for the Loaded and/or Unloaded events, set the // flag that says we want to receive it. Otherwise, if it was set in the old template, clear it. UpdateLoadedFlag( container, oldFrameworkTemplate, newFrameworkTemplate ); // Wipe out VisualTree only if VisualTree factories // are changing // // If the factories are null for both new and old, then, the Template // has the opportunity to supply the VisualTree using the "BuildVisualTree" // virtual. FrameworkElementFactory oldFactory; FrameworkElementFactory newFactory; bool canBuildVisualTree; bool hasTemplateGeneratedSubTree; FrugalStructList<ContainerDependent> oldContainerDependents; FrugalStructList<ContainerDependent> newContainerDependents; Debug.Assert(feContainer != null); oldFactory = (oldFrameworkTemplate != null) ? oldFrameworkTemplate.VisualTree : null; newFactory = (newFrameworkTemplate != null) ? newFrameworkTemplate.VisualTree : null; canBuildVisualTree = (oldFrameworkTemplate != null) ? oldFrameworkTemplate.CanBuildVisualTree : false; hasTemplateGeneratedSubTree = feContainer.HasTemplateGeneratedSubTree; oldContainerDependents = (oldFrameworkTemplate != null) ? oldFrameworkTemplate.ContainerDependents : StyleHelper.EmptyContainerDependents; newContainerDependents = (newFrameworkTemplate != null) ? newFrameworkTemplate.ContainerDependents : StyleHelper.EmptyContainerDependents; if (hasTemplateGeneratedSubTree) { StyleHelper.ClearGeneratedSubTree(oldTemplateData, feContainer /* fe */, null /* fce */, oldFrameworkTemplate ); } // Propagate invalidation for template dependents FrugalStructList<ContainerDependent> exclusionContainerDependents = new FrugalStructList<ContainerDependent>(); StyleHelper.InvalidateContainerDependents(container, ref exclusionContainerDependents, ref oldContainerDependents, ref newContainerDependents); // Propagate invalidation for resource references that may be // picking stuff from the style's ResourceDictionary DoTemplateResourcesInvalidations(container, feContainer, null /*fce*/, oldTemplate, newTemplate); Debug.Assert(feContainer != null); feContainer.OnTemplateChangedInternal(oldFrameworkTemplate, newFrameworkTemplate); } else { // // Template is not changing // // Template was invalidated but didn't change. If the Template created the // VisualTree via an override of BuildVisualTree, then, it is // wiped out now so that it may be conditionally rebuilt by the // custom Template if (newFrameworkTemplate != null) { if (feContainer.HasTemplateGeneratedSubTree && newFrameworkTemplate.VisualTree == null && !newFrameworkTemplate.HasXamlNodeContent ) { StyleHelper.ClearGeneratedSubTree(oldTemplateData, feContainer /* fe */, null /* fce */, oldFrameworkTemplate); // Nothing guarantees that ApplyTemplate actually gets // called, so ask for it explicitly (bug 963163). feContainer.InvalidateMeasure(); } } } }