// Helper method to retrieve and fire Clr Event handlers for DependencyPropertyChanged event private void RaiseDependencyPropertyChanged(EventPrivateKey key, DependencyPropertyChangedEventArgs args) { EventHandlersStore store = EventHandlersStore; if (store != null) { Delegate handler = store.Get(key); if (handler != null) { ((DependencyPropertyChangedEventHandler)handler)(this, args); } } }
private void RaiseMouseButtonEvent(EventPrivateKey key, MouseButtonEventArgs e) { EventHandlersStore store = EventHandlersStore; if (store != null) { Delegate handler = store.Get(key); if (handler != null) { ((MouseButtonEventHandler)handler)(this, e); } } }
// Helper method to retrieve and fire the InheritedPropertyChanged event internal void RaiseInheritedPropertyChangedEvent(ref InheritablePropertyChangeInfo info) { EventHandlersStore store = EventHandlersStore; if (store != null) { Delegate handler = store.Get(FrameworkElement.InheritedPropertyChangedKey); if (handler != null) { InheritedPropertyChangedEventArgs args = new InheritedPropertyChangedEventArgs(ref info); ((InheritedPropertyChangedEventHandler)handler)(this, args); } } }
// Iterates through the setters collection and adds the EventSetter information into // an EventHandlersStore for easy and fast retrieval during event routing. Also adds // an entry in the EventDependents list for EventhandlersStore holding the TargetType's // events. private void ProcessSetters(Style style) { // Walk down to bottom of based-on chain if (style == null) { return; } style.Setters.Seal(); // Does not mark individual setters as sealed, that's up to the loop below. // On-demand create the PropertyValues list, so that we can specify the right size. if(PropertyValues.Count == 0) { PropertyValues = new FrugalStructList<System.Windows.PropertyValue>(style.Setters.Count); } // Add EventSetters to local EventHandlersStore for (int i = 0; i < style.Setters.Count; i++) { SetterBase setterBase = style.Setters[i]; Debug.Assert(setterBase != null, "Setter collection must contain non-null instances of SetterBase"); // Setters are folded into the PropertyValues table only for the current style. The // processing of BasedOn Style properties will occur in subsequent call to ProcessSelfStyle Setter setter = setterBase as Setter; if (setter != null) { // Style Setters are not allowed to have a child target name - since there are no child nodes in a Style. if( setter.TargetName != null ) { throw new InvalidOperationException(SR.Get(SRID.SetterOnStyleNotAllowedToHaveTarget, setter.TargetName)); } if (style == this) { DynamicResourceExtension dynamicResource = setter.ValueInternal as DynamicResourceExtension; if (dynamicResource == null) { UpdatePropertyValueList( setter.Property, PropertyValueType.Set, setter.ValueInternal ); } else { UpdatePropertyValueList( setter.Property, PropertyValueType.Resource, dynamicResource.ResourceKey ); } } } else { Debug.Assert(setterBase is EventSetter, "Unsupported SetterBase subclass in style triggers ({0})", setterBase.GetType().ToString()); // Add this to the _eventHandlersStore EventSetter eventSetter = (EventSetter)setterBase; if (_eventHandlersStore == null) { _eventHandlersStore = new EventHandlersStore(); } _eventHandlersStore.AddRoutedEventHandler(eventSetter.Event, eventSetter.Handler, eventSetter.HandledEventsToo); SetModified(HasEventSetter); // If this event setter watches the loaded/unloaded events, set the optimization // flag. if (eventSetter.Event == FrameworkElement.LoadedEvent || eventSetter.Event == FrameworkElement.UnloadedEvent) { _hasLoadedChangeHandler = true; } } } // Process EventSetters on based on style so they get merged // into the EventHandlersStore for the current style. ProcessSetters(style._basedOn); }
/// <summary> /// Copy constructor for EventHandlersStore /// </summary> public EventHandlersStore(EventHandlersStore source) { _entries = source._entries; }
// Iterates through the setters collection and adds the EventSetter information into // an EventHandlersStore for easy and fast retrieval during event routing. Also adds // an entry in the EventDependents list for EventhandlersStore holding the TargetType's // events. private void ProcessSetters(Style style) { // Walk down to bottom of based-on chain if (style == null) { return; } style.Setters.Seal(); // Does not mark individual setters as sealed, that's up to the loop below. // On-demand create the PropertyValues list, so that we can specify the right size. if (PropertyValues.Count == 0) { PropertyValues = new FrugalStructList <System.Windows.PropertyValue>(style.Setters.Count); } // Add EventSetters to local EventHandlersStore for (int i = 0; i < style.Setters.Count; i++) { SetterBase setterBase = style.Setters[i]; Debug.Assert(setterBase != null, "Setter collection must contain non-null instances of SetterBase"); // Setters are folded into the PropertyValues table only for the current style. The // processing of BasedOn Style properties will occur in subsequent call to ProcessSelfStyle Setter setter = setterBase as Setter; if (setter != null) { // Style Setters are not allowed to have a child target name - since there are no child nodes in a Style. if (setter.TargetName != null) { throw new InvalidOperationException(SR.Get(SRID.SetterOnStyleNotAllowedToHaveTarget, setter.TargetName)); } if (style == this) { DynamicResourceExtension dynamicResource = setter.ValueInternal as DynamicResourceExtension; if (dynamicResource == null) { UpdatePropertyValueList(setter.Property, PropertyValueType.Set, setter.ValueInternal); } else { UpdatePropertyValueList(setter.Property, PropertyValueType.Resource, dynamicResource.ResourceKey); } } } else { Debug.Assert(setterBase is EventSetter, "Unsupported SetterBase subclass in style triggers ({0})", setterBase.GetType().ToString()); // Add this to the _eventHandlersStore EventSetter eventSetter = (EventSetter)setterBase; if (_eventHandlersStore == null) { _eventHandlersStore = new EventHandlersStore(); } _eventHandlersStore.AddRoutedEventHandler(eventSetter.Event, eventSetter.Handler, eventSetter.HandledEventsToo); SetModified(HasEventSetter); // If this event setter watches the loaded/unloaded events, set the optimization // flag. if (eventSetter.Event == FrameworkElement.LoadedEvent || eventSetter.Event == FrameworkElement.UnloadedEvent) { _hasLoadedChangeHandler = true; } } } // Process EventSetters on based on style so they get merged // into the EventHandlersStore for the current style. ProcessSetters(style._basedOn); }
/// <summary> /// Add an event handler for the given routed event. This action applies to the instances created by this factory /// </summary> public void AddHandler(RoutedEvent routedEvent, Delegate handler, bool handledEventsToo) { if (_sealed) { throw new InvalidOperationException(SR.Get(SRID.CannotChangeAfterSealed, "FrameworkElementFactory")); } if (routedEvent == null) { throw new ArgumentNullException("routedEvent"); } if (handler == null) { throw new ArgumentNullException("handler"); } if (handler.GetType() != routedEvent.HandlerType) { throw new ArgumentException(SR.Get(SRID.HandlerTypeIllegal)); } if (_eventHandlersStore == null) { _eventHandlersStore = new EventHandlersStore(); } _eventHandlersStore.AddRoutedEventHandler(routedEvent, handler, handledEventsToo); // Keep track of whether we're listening to the loaded or unloaded events; // if so, we have to trigger a listener in the FE/FCE (as a performance // optimization). if ( (routedEvent == FrameworkElement.LoadedEvent) ||(routedEvent == FrameworkElement.UnloadedEvent)) { HasLoadedChangeHandler = true; } }
// // 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); } }
// // 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)); } } } }
// =========================================================================== // 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)); } }
//+--------------------------------------------------------------------------------------- // // 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); } }
/// <summary> /// Adds a delegate to the list of event handlers on this object. /// </summary> /// <param name="key"> /// A unique identifier for the event handler. /// </param> /// <param name="handler">The delegate to add.</param> private void AddEventHandler(EventPrivateKey key, Delegate handler) { WritePreamble(); EventHandlersStore store = EventHandlersStoreField.GetValue(this); if (store == null) { store = new EventHandlersStore(); EventHandlersStoreField.SetValue(this, store); } store.Add(key, handler); WritePostscript(); }