public DTypeMap(int entryCount) { // Constant Time Lookup entries (array size) _entryCount = entryCount; _entries = new object[_entryCount]; _activeDTypes = new ItemStructList<DependencyObjectType>(128); }
// Returns a copy of the list of registered RoutedEvents // Returns a copy of the list so the original cannot be modified internal static RoutedEvent[] GetRoutedEvents() { RoutedEvent[] routedEvents; lock (Synchronized) { // Requires GlobalLock to access _countRoutedEvents routedEvents = new RoutedEvent[_countRoutedEvents]; // Enumerate through all of the RoutedEvents in the DTypeMap // Requires GlobalLock to access _dTypedRoutedEventList ItemStructList <DependencyObjectType> keys = _dTypedRoutedEventList.ActiveDTypes; int destIndex = 0; for (int i = 0; i < keys.Count; i++) { FrugalObjectList <RoutedEvent> dTypedRoutedEventList = (FrugalObjectList <RoutedEvent>)_dTypedRoutedEventList[keys.List[i]]; for (int j = 0; j < dTypedRoutedEventList.Count; j++) { RoutedEvent routedEvent = dTypedRoutedEventList[j]; if (Array.IndexOf(routedEvents, routedEvent) < 0) { routedEvents[destIndex++] = routedEvent; } } } // Enumerate through all of the RoutedEvents in the Hashtable // Requires GlobalLock to access _ownerTypedRoutedEventList IDictionaryEnumerator htEnumerator = _ownerTypedRoutedEventList.GetEnumerator(); while (htEnumerator.MoveNext() == true) { FrugalObjectList <RoutedEvent> ownerRoutedEventList = (FrugalObjectList <RoutedEvent>)htEnumerator.Value; for (int j = 0; j < ownerRoutedEventList.Count; j++) { RoutedEvent routedEvent = ownerRoutedEventList[j]; if (Array.IndexOf(routedEvents, routedEvent) < 0) { routedEvents[destIndex++] = routedEvent; } } } } return(routedEvents); }
// Register a Class Handler // NOTE: Handler Type must be the // same as the one specified when // registering the corresponding RoutedEvent internal static void RegisterClassHandler( Type classType, RoutedEvent routedEvent, Delegate handler, bool handledEventsToo) { Debug.Assert( typeof(UIElement).IsAssignableFrom(classType) || typeof(ContentElement).IsAssignableFrom(classType) || typeof(UIElement3D).IsAssignableFrom(classType), "Class Handlers can be registered only for UIElement/ContentElement/UIElement3D and their sub types"); Debug.Assert(routedEvent.IsLegalHandler(handler), "Handler Type mismatch"); ClassHandlersStore classListenersLists; int index; // We map the classType to a DType use DTypeMap for storage DependencyObjectType dType = DependencyObjectType.FromSystemTypeInternal(classType); // Get the updated EventHandlersStore for the given DType GetDTypedClassListeners(dType, routedEvent, out classListenersLists, out index); // Reuired to update storage lock (Synchronized) { // Add new routed event handler and get the updated set of handlers RoutedEventHandlerInfoList updatedClassListeners = classListenersLists.AddToExistingHandlers(index, handler, handledEventsToo); // Update Sub Classes ItemStructList <DependencyObjectType> keys = _dTypedClassListeners.ActiveDTypes; for (int i = 0; i < keys.Count; i++) { if (keys.List[i].IsSubclassOf(dType) == true) { classListenersLists = (ClassHandlersStore)_dTypedClassListeners[keys.List[i]]; classListenersLists.UpdateSubClassHandlers(routedEvent, updatedClassListeners); } } } }
// Constructor for ClassHandlersStore internal ClassHandlersStore(int size) { _eventHandlersList = new ItemStructList <ClassHandlers>(size); }
// // This method // 1. Adds shared table entries for property values set via Triggers // private static void ProcessTemplateTriggers( TriggerCollection triggers, FrameworkTemplate frameworkTemplate, ref FrugalStructList<ChildRecord> childRecordFromChildIndex, ref FrugalStructList<ItemStructMap<TriggerSourceRecord>> triggerSourceRecordFromChildIndex, ref FrugalStructList<ContainerDependent> containerDependents, ref FrugalStructList<ChildPropertyDependent> resourceDependents, ref ItemStructList<ChildEventDependent> eventDependents, ref HybridDictionary dataTriggerRecordFromBinding, HybridDictionary childIndexFromChildID, ref bool hasInstanceValues, ref HybridDictionary triggerActions, FrameworkElementFactory templateRoot, ref EventHandlersStore eventHandlersStore, ref FrugalMap propertyTriggersWithActions, ref HybridDictionary dataTriggersWithActions, ref bool hasLoadedChangeHandler) { if (triggers != null) { int triggerCount = triggers.Count; for (int i = 0; i < triggerCount; i++) { TriggerBase triggerBase = triggers[i]; Trigger trigger; MultiTrigger multiTrigger; DataTrigger dataTrigger; MultiDataTrigger multiDataTrigger; EventTrigger eventTrigger; DetermineTriggerType( triggerBase, out trigger, out multiTrigger, out dataTrigger, out multiDataTrigger, out eventTrigger ); if ( trigger != null || multiTrigger != null|| dataTrigger != null || multiDataTrigger != null ) { // Update the SourceChildIndex for each of the conditions for this trigger TriggerCondition[] conditions = triggerBase.TriggerConditions; for (int k=0; k<conditions.Length; k++) { conditions[k].SourceChildIndex = StyleHelper.QueryChildIndexFromChildName(conditions[k].SourceName, childIndexFromChildID); } // Set things up to handle Setter values for (int j = 0; j < triggerBase.PropertyValues.Count; j++) { PropertyValue propertyValue = triggerBase.PropertyValues[j]; // Check for trigger rules that act on template children if (propertyValue.ChildName == StyleHelper.SelfName) { // "Self" (container) trigger // Track properties on the container that are being driven by // the Template so that they can be invalidated during Template changes StyleHelper.AddContainerDependent(propertyValue.Property, true /*fromVisualTrigger*/, ref containerDependents); } StyleHelper.UpdateTables(ref propertyValue, ref childRecordFromChildIndex, ref triggerSourceRecordFromChildIndex, ref resourceDependents, ref dataTriggerRecordFromBinding, childIndexFromChildID, ref hasInstanceValues); } // Set things up to handle TriggerActions if( triggerBase.HasEnterActions || triggerBase.HasExitActions ) { if( trigger != null ) { StyleHelper.AddPropertyTriggerWithAction( triggerBase, trigger.Property, ref propertyTriggersWithActions ); } else if( multiTrigger != null ) { for( int k = 0; k < multiTrigger.Conditions.Count; k++ ) { Condition triggerCondition = multiTrigger.Conditions[k]; StyleHelper.AddPropertyTriggerWithAction( triggerBase, triggerCondition.Property, ref propertyTriggersWithActions ); } } else if( dataTrigger != null ) { StyleHelper.AddDataTriggerWithAction( triggerBase, dataTrigger.Binding, ref dataTriggersWithActions ); } else if( multiDataTrigger != null ) { for( int k = 0; k < multiDataTrigger.Conditions.Count; k++ ) { Condition dataCondition = multiDataTrigger.Conditions[k]; StyleHelper.AddDataTriggerWithAction( triggerBase, dataCondition.Binding, ref dataTriggersWithActions ); } } else { throw new InvalidOperationException(SR.Get(SRID.UnsupportedTriggerInTemplate, triggerBase.GetType().Name)); } } } else if( eventTrigger != null ) { StyleHelper.ProcessEventTrigger(eventTrigger, childIndexFromChildID, ref triggerActions, ref eventDependents, templateRoot, frameworkTemplate, ref eventHandlersStore, ref hasLoadedChangeHandler); } else { throw new InvalidOperationException(SR.Get(SRID.UnsupportedTriggerInTemplate, triggerBase.GetType().Name)); } } } }
// Constructor for ClassHandlersStore internal ClassHandlersStore(int size) { _eventHandlersList = new ItemStructList<ClassHandlers>(size); }
// // All table datastructures read-lock-free/write-lock // AddEventDependent writes the datastructures, locks set by callers // // This method // 1. Adds an EventDependent to the EventDependents list. This is used // to lookup events in styles during event routing. // internal static void AddEventDependent( int childIndex, EventHandlersStore eventHandlersStore, ref ItemStructList<ChildEventDependent> eventDependents) { if (eventHandlersStore != null) { Debug.Assert(childIndex >= 0); ChildEventDependent dependent = new ChildEventDependent(); dependent.ChildIndex = childIndex; dependent.EventHandlersStore = eventHandlersStore; eventDependents.Add(ref dependent); } }
//+---------------------------------------------------------------------------------------------- // // ProcessTemplateContentFromFEF // // This method walks the FEF tree and builds the shared tables from the property values // in the FEF. // // For the Baml templates (non-FEF), see the ProcessTemplateContent routine. // //+---------------------------------------------------------------------------------------------- internal static void ProcessTemplateContentFromFEF( FrameworkElementFactory factory, ref FrugalStructList<ChildRecord> childRecordFromChildIndex, ref FrugalStructList<ItemStructMap<TriggerSourceRecord>> triggerSourceRecordFromChildIndex, ref FrugalStructList<ChildPropertyDependent> resourceDependents, ref ItemStructList<ChildEventDependent> eventDependents, ref HybridDictionary dataTriggerRecordFromBinding, HybridDictionary childIndexFromChildID, ref bool hasInstanceValues) { // Process the PropertyValues on the current node for (int i = 0; i < factory.PropertyValues.Count; i++) { PropertyValue propertyValue = factory.PropertyValues[i]; StyleHelper.UpdateTables(ref propertyValue, ref childRecordFromChildIndex, ref triggerSourceRecordFromChildIndex, ref resourceDependents, ref dataTriggerRecordFromBinding, childIndexFromChildID, ref hasInstanceValues); } // Add an entry in the EventDependents list for // the current TemplateNode's EventHandlersStore. StyleHelper.AddEventDependent(factory._childIndex, factory.EventHandlersStore, ref eventDependents); // Traverse the children of this TemplateNode factory = factory.FirstChild; while (factory != null) { ProcessTemplateContentFromFEF(factory, ref childRecordFromChildIndex, ref triggerSourceRecordFromChildIndex, ref resourceDependents, ref eventDependents, ref dataTriggerRecordFromBinding, childIndexFromChildID, ref hasInstanceValues); factory = factory.NextSibling; } }
// =========================================================================== // These methods are invoked when a Style/Template is Sealed // =========================================================================== #region WriteMethods // // This method // 1. Seals a template // internal static void SealTemplate( FrameworkTemplate frameworkTemplate, ref bool isSealed, FrameworkElementFactory templateRoot, TriggerCollection triggers, ResourceDictionary resources, HybridDictionary childIndexFromChildID, ref FrugalStructList<ChildRecord> childRecordFromChildIndex, ref FrugalStructList<ItemStructMap<TriggerSourceRecord>> triggerSourceRecordFromChildIndex, ref FrugalStructList<ContainerDependent> containerDependents, ref FrugalStructList<ChildPropertyDependent> resourceDependents, ref ItemStructList<ChildEventDependent> eventDependents, ref HybridDictionary triggerActions, ref HybridDictionary dataTriggerRecordFromBinding, ref bool hasInstanceValues, ref EventHandlersStore eventHandlersStore) { Debug.Assert(frameworkTemplate != null ); // This template has already been sealed. // There is no more to do. if (isSealed) { return; } // Seal template nodes (if exists) if (frameworkTemplate != null) { frameworkTemplate.ProcessTemplateBeforeSeal(); } if (templateRoot != null) { Debug.Assert( !frameworkTemplate.HasXamlNodeContent ); // Seal the template Debug.Assert(frameworkTemplate != null); //frameworkTemplate.ProcessTemplateBeforeSeal(); templateRoot.Seal(frameworkTemplate); } // Seal triggers if (triggers != null) { triggers.Seal(); } // Seal Resource Dictionary if (resources != null) { resources.IsReadOnly = true; } // Build shared tables if (templateRoot != null) { // This is a FEF-style template. Process the root node, and it will // recurse through the rest of the FEF tree. StyleHelper.ProcessTemplateContentFromFEF( templateRoot, ref childRecordFromChildIndex, ref triggerSourceRecordFromChildIndex, ref resourceDependents, ref eventDependents, ref dataTriggerRecordFromBinding, childIndexFromChildID, ref hasInstanceValues); } // Process Triggers. (Trigger PropertyValues are inserted // last into the Style/Template GetValue chain because they // are the highest priority) bool hasHandler = false; Debug.Assert( frameworkTemplate != null ); StyleHelper.ProcessTemplateTriggers( triggers, frameworkTemplate, ref childRecordFromChildIndex, ref triggerSourceRecordFromChildIndex, ref containerDependents, ref resourceDependents, ref eventDependents, ref dataTriggerRecordFromBinding, childIndexFromChildID, ref hasInstanceValues, ref triggerActions, templateRoot, ref eventHandlersStore, ref frameworkTemplate.PropertyTriggersWithActions, ref frameworkTemplate.DataTriggersWithActions, ref hasHandler ); frameworkTemplate.HasLoadedChangeHandler = hasHandler; frameworkTemplate.SetResourceReferenceState(); // All done, seal self and call it a day. isSealed = true; // Remove thread affinity so it can be accessed across threads frameworkTemplate.DetachFromDispatcher(); // Check if the template has the Template property set on the container via its visual triggers. // It is an error to specify the TemplateProperty in your own Template. if (StyleHelper.IsSetOnContainer(Control.TemplateProperty, ref containerDependents, true) || StyleHelper.IsSetOnContainer(ContentPresenter.TemplateProperty, ref containerDependents, true)) { throw new InvalidOperationException(SR.Get(SRID.CannotHavePropertyInTemplate, Control.TemplateProperty.Name)); } // Check if the template has the Style property set on the container via its visual triggers. // It is an error to specify the StyleProperty in your own Template. if (StyleHelper.IsSetOnContainer(FrameworkElement.StyleProperty, ref containerDependents, true)) { throw new InvalidOperationException(SR.Get(SRID.CannotHavePropertyInTemplate, FrameworkElement.StyleProperty.Name)); } // Check if the template has the DefaultStyleKey property set on the container via its visual triggers. // It is an error to specify the DefaultStyleKeyProperty in your own Template. if (StyleHelper.IsSetOnContainer(FrameworkElement.DefaultStyleKeyProperty, ref containerDependents, true)) { throw new InvalidOperationException(SR.Get(SRID.CannotHavePropertyInTemplate, FrameworkElement.DefaultStyleKeyProperty.Name)); } // Check if the template has the OverridesDefaultStyle property set on the container via its visual triggers. // It is an error to specify the OverridesDefaultStyleProperty in your own Template. if (StyleHelper.IsSetOnContainer(FrameworkElement.OverridesDefaultStyleProperty, ref containerDependents, true)) { throw new InvalidOperationException(SR.Get(SRID.CannotHavePropertyInTemplate, FrameworkElement.OverridesDefaultStyleProperty.Name)); } // Check if the template has the Name property set on the container via its visual triggers. // It is an error to specify the Name in your own Template. if (StyleHelper.IsSetOnContainer(FrameworkElement.NameProperty, ref containerDependents, true)) { throw new InvalidOperationException(SR.Get(SRID.CannotHavePropertyInTemplate, FrameworkElement.NameProperty.Name)); } }
// =========================================================================== // These methods are used to query Style/Template // eventhandlers during event routing // =========================================================================== #region ReadEvents // // This method // Gets the handlers of a template child // (Index is '0' when the styled container is asking) // internal static RoutedEventHandlerInfo[] GetChildRoutedEventHandlers( int childIndex, RoutedEvent routedEvent, ref ItemStructList<ChildEventDependent> eventDependents) { Debug.Assert(routedEvent != null); if (childIndex > 0) { // Find the EventHandlersStore that matches the given childIndex EventHandlersStore eventHandlersStore = null; for (int i=0; i<eventDependents.Count; i++) { if (eventDependents.List[i].ChildIndex == childIndex) { eventHandlersStore = eventDependents.List[i].EventHandlersStore; break; } } if (eventHandlersStore != null) { return eventHandlersStore.GetRoutedEventHandlers(routedEvent); } } return null; }
// // 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; }
// // This method // 1. Adds or removes per-instance state on the container/child (push model) // 2. Processes values that need per-instance storage // private static void ProcessInstanceValuesHelper( ref ItemStructList<ChildValueLookup> valueLookupList, DependencyObject target, int childIndex, HybridDictionary instanceValues, bool apply) { // update all properties whose value needs per-instance storage for (int i = valueLookupList.Count - 1; i >= 0; --i) { switch (valueLookupList.List[i].LookupType) { case ValueLookupType.Simple: case ValueLookupType.Trigger: case ValueLookupType.DataTrigger: Freezable freezable; DependencyProperty dp = valueLookupList.List[i].Property; object o = valueLookupList.List[i].Value; if (o is MarkupExtension) { ProcessInstanceValue(target, childIndex, instanceValues, dp, i, apply); } else if ((freezable = o as Freezable) != null) { if (freezable.CheckAccess()) { if (!freezable.IsFrozen) { ProcessInstanceValue(target, childIndex, instanceValues, dp, i, apply); } } else { Debug.Assert(!freezable.CanFreeze, "If a freezable could have been frozen it would have been done by now."); throw new InvalidOperationException(SR.Get(SRID.CrossThreadAccessOfUnshareableFreezable, freezable.GetType().FullName)); } } break; } } }
//+--------------------------------------------------------------------------------------- // // AddDelegateToFireTrigger // // Add the EventTriggerHandlerOnChild to listen for an event, like the above overload // except this is for baml-style templates, rather than FEF-style. // //+--------------------------------------------------------------------------------------- private static void AddDelegateToFireTrigger( RoutedEvent routedEvent, int childIndex, ref ItemStructList<ChildEventDependent> eventDependents, ref EventHandlersStore eventHandlersStore) { Debug.Assert( childIndex != 0 ); // This should go to the other AddDelegateToFireTrigger overload if (eventHandlersStore == null) { eventHandlersStore = new EventHandlersStore(); } StyleHelper.AddEventDependent( childIndex, eventHandlersStore, ref eventDependents ); eventHandlersStore.AddRoutedEventHandler(routedEvent, StyleHelper.EventTriggerHandlerOnChild, false/* HandledEventsToo */); }
// // This method // 1. Adds a delegate that will get called during event routing and // will allow us to invoke the TriggerActions // private static void AddDelegateToFireTrigger( RoutedEvent routedEvent, int childIndex, FrameworkElementFactory templateRoot, FrameworkElementFactory childFef, ref ItemStructList<ChildEventDependent> eventDependents, ref EventHandlersStore eventHandlersStore) { if (childIndex == 0) { if (eventHandlersStore == null) { eventHandlersStore = new EventHandlersStore(); // Add an entry in the EventDependents list for // the TargetType's EventHandlersStore. Notice // that the childIndex is 0. StyleHelper.AddEventDependent(0, eventHandlersStore, ref eventDependents); } eventHandlersStore.AddRoutedEventHandler(routedEvent, StyleHelper.EventTriggerHandlerOnContainer, false/* HandledEventsToo */); } else { //FrameworkElementFactory fef = StyleHelper.FindFEF(templateRoot, childIndex); if (childFef.EventHandlersStore == null) { childFef.EventHandlersStore = new EventHandlersStore(); // Add an entry in the EventDependents list for // the current FEF's EventHandlersStore. StyleHelper.AddEventDependent(childIndex, childFef.EventHandlersStore, ref eventDependents); } childFef.EventHandlersStore.AddRoutedEventHandler(routedEvent, StyleHelper.EventTriggerHandlerOnChild, false/* HandledEventsToo */); } }
// // This method // 1. Adds the trigger information to the data structure that will be // used when it's time to add the delegate to the event route. // internal static void ProcessEventTrigger ( EventTrigger eventTrigger, HybridDictionary childIndexFromChildName, ref HybridDictionary triggerActions, ref ItemStructList<ChildEventDependent> eventDependents, FrameworkElementFactory templateRoot, FrameworkTemplate frameworkTemplate, ref EventHandlersStore eventHandlersStore, ref bool hasLoadedChangeHandler) { if( eventTrigger == null ) { return; } // The list of actions associated with the event of this EventTrigger. List<TriggerAction> actionsList = null; bool actionsListExisted = true; bool actionsListChanged = false; TriggerAction action = null; FrameworkElementFactory childFef = null; // Find a ChildID for the EventTrigger. if( eventTrigger.SourceName == null ) { eventTrigger.TriggerChildIndex = 0; } else { int childIndex = StyleHelper.QueryChildIndexFromChildName(eventTrigger.SourceName, childIndexFromChildName); if( childIndex == -1 ) { throw new InvalidOperationException(SR.Get(SRID.EventTriggerTargetNameUnresolvable, eventTrigger.SourceName)); } eventTrigger.TriggerChildIndex = childIndex; } // We have at least one EventTrigger - will need triggerActions // if it doesn't already exist if (triggerActions == null) { triggerActions = new HybridDictionary(); } else { actionsList = triggerActions[eventTrigger.RoutedEvent] as List<TriggerAction>; } // Set up TriggerAction list if one doesn't already exist if (actionsList == null) { actionsListExisted = false; actionsList = new List<TriggerAction>(); } for (int i = 0; i < eventTrigger.Actions.Count; i++) { action = eventTrigger.Actions[i]; // Any reason we shouldn't use this TriggerAction? Check here. if( false /* No reason not to use it right now */ ) { // continue; } // Looks good, add to list. Debug.Assert(action.IsSealed, "TriggerAction should have already been sealed by this point."); actionsList.Add(action); actionsListChanged = true; } if (actionsListChanged && !actionsListExisted) { triggerActions[eventTrigger.RoutedEvent] = actionsList; } // Add a special delegate to listen for this event and // fire the trigger. if( templateRoot != null || eventTrigger.TriggerChildIndex == 0 ) { // This is a FEF-style template, or the trigger is keying off of // the templated parent. // Get the FEF that is referenced by this trigger. if (eventTrigger.TriggerChildIndex != 0) { childFef = StyleHelper.FindFEF(templateRoot, eventTrigger.TriggerChildIndex); } // If this trigger needs the loaded/unloaded events, set the optimization // flag. if ( (eventTrigger.RoutedEvent == FrameworkElement.LoadedEvent) ||(eventTrigger.RoutedEvent == FrameworkElement.UnloadedEvent)) { if (eventTrigger.TriggerChildIndex == 0) { // Mark the template to show it has a loaded or unloaded handler hasLoadedChangeHandler = true; } else { // Mark the FEF to show it has a loaded or unloaded handler childFef.HasLoadedChangeHandler = true; } } // Add a delegate that'll come back and fire these actions. // This information will be used by FrameworkElement.AddStyleHandlersToEventRoute StyleHelper.AddDelegateToFireTrigger(eventTrigger.RoutedEvent, eventTrigger.TriggerChildIndex, templateRoot, childFef, ref eventDependents, ref eventHandlersStore); } else { // This is a baml-style template. // If this trigger needs the loaded/unloaded events, set the optimization // flag. if (eventTrigger.RoutedEvent == FrameworkElement.LoadedEvent || eventTrigger.RoutedEvent == FrameworkElement.UnloadedEvent ) { FrameworkTemplate.TemplateChildLoadedFlags templateChildLoadedFlags = frameworkTemplate._TemplateChildLoadedDictionary[ eventTrigger.TriggerChildIndex ] as FrameworkTemplate.TemplateChildLoadedFlags; if( templateChildLoadedFlags == null ) { templateChildLoadedFlags = new FrameworkTemplate.TemplateChildLoadedFlags(); frameworkTemplate._TemplateChildLoadedDictionary[ eventTrigger.TriggerChildIndex ] = templateChildLoadedFlags; } if( eventTrigger.RoutedEvent == FrameworkElement.LoadedEvent ) { templateChildLoadedFlags.HasLoadedChangedHandler = true; } else { templateChildLoadedFlags.HasUnloadedChangedHandler = true; } } // Add a delegate that'll come back and fire these actions. StyleHelper.AddDelegateToFireTrigger(eventTrigger.RoutedEvent, eventTrigger.TriggerChildIndex, ref eventDependents, ref eventHandlersStore); } }