// This block of code attempts to minimize the number of // type operations and assignments involved in figuring out what // trigger type we're dealing here. // Attempted casts are done in the order of decreasing expected frequency. // rearrange as expectations change. private static void DetermineTriggerType( TriggerBase triggerBase, out Trigger trigger, out MultiTrigger multiTrigger, out DataTrigger dataTrigger, out MultiDataTrigger multiDataTrigger, out EventTrigger eventTrigger ) { if( (trigger = (triggerBase as Trigger)) != null ) { multiTrigger = null; dataTrigger = null; multiDataTrigger = null; eventTrigger = null; } else if( (multiTrigger = (triggerBase as MultiTrigger)) != null ) { dataTrigger = null; multiDataTrigger = null; eventTrigger = null; } else if( (dataTrigger = (triggerBase as DataTrigger)) != null ) { multiDataTrigger = null; eventTrigger = null; } else if( (multiDataTrigger = (triggerBase as MultiDataTrigger)) != null ) { eventTrigger = null; } else if( (eventTrigger = (triggerBase as EventTrigger)) != null ) { ; // Do nothing - eventTrigger is now non-null, and everything else has been set to null. } else { // None of the above - the caller is expected to throw an exception // stating that the trigger type is not supported. } }
public static TriggerItemBase GetTriggerItem(TriggerBase trigger, FrameworkElement source, TriggerSource triggerSource) { TriggerItemBase triggerItem; if (trigger is Trigger) { triggerItem = new TriggerItem((Trigger)trigger, source, triggerSource); } else if (trigger is DataTrigger) { triggerItem = new DataTriggerItem((DataTrigger)trigger, source, triggerSource); } else if (trigger is MultiTrigger) { triggerItem = new MultiTriggerItem((MultiTrigger)trigger, source, triggerSource); } else if (trigger is MultiDataTrigger) { triggerItem = new MultiDataTriggerItem((MultiDataTrigger)trigger, source, triggerSource); } else { return null; } triggerItem.Initialize(); return triggerItem; }
/// <summary> /// Seal this TriggerAction to prevent further updates /// </summary> /// <remarks> /// TriggerActionCollection will call this method to seal individual /// TriggerAction objects. We do some check here then call the /// parameter-less Seal() so subclasses can also do what they need to do. /// </remarks> internal void Seal( TriggerBase containingTrigger ) { if( IsSealed && containingTrigger != _containingTrigger ) { throw new InvalidOperationException(SR.Get(SRID.TriggerActionMustBelongToASingleTrigger)); } _containingTrigger = containingTrigger; Seal(); }
// Token: 0x06000C8B RID: 3211 RVA: 0x0002F2E4 File Offset: 0x0002D4E4 internal void Seal(TriggerBase containingTrigger) { if (base.IsSealed && containingTrigger != this._containingTrigger) { throw new InvalidOperationException(SR.Get("TriggerActionMustBelongToASingleTrigger")); } this._containingTrigger = containingTrigger; this.Seal(); }
// Token: 0x060003F8 RID: 1016 RVA: 0x0000B5E0 File Offset: 0x000097E0 internal static void DisconnectOneTrigger(FrameworkElement triggersHost, TriggerBase triggerBase) { EventTrigger eventTrigger = triggerBase as EventTrigger; if (eventTrigger != null) { eventTrigger._source.RemoveHandler(eventTrigger.RoutedEvent, eventTrigger._routedEventHandler); eventTrigger._routedEventHandler = null; return; } throw new InvalidOperationException(SR.Get("TriggersSupportsEventTriggersOnly")); }
// Token: 0x060003F6 RID: 1014 RVA: 0x0000B538 File Offset: 0x00009738 internal static void ProcessOneTrigger(FrameworkElement triggersHost, TriggerBase triggerBase) { EventTrigger eventTrigger = triggerBase as EventTrigger; if (eventTrigger != null) { eventTrigger._source = FrameworkElement.FindNamedFrameworkElement(triggersHost, eventTrigger.SourceName); EventTrigger.EventTriggerSourceListener @object = new EventTrigger.EventTriggerSourceListener(eventTrigger, triggersHost); eventTrigger._routedEventHandler = new RoutedEventHandler(@object.Handler); eventTrigger._source.AddHandler(eventTrigger.RoutedEvent, eventTrigger._routedEventHandler, false); return; } throw new InvalidOperationException(SR.Get("TriggersSupportsEventTriggersOnly")); }
// 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 ); }
private void ProcessVisualTriggers(Style style) { // Walk down to bottom of based-on chain if (style == null) { return; } ProcessVisualTriggers(style._basedOn); if (style._visualTriggers != null) { // Merge in "self" and child TriggerBase PropertyValues while walking // back up the tree. "Based-on" style rules are always added first // (lower priority) int triggerCount = style._visualTriggers.Count; for (int i = 0; i < triggerCount; i++) { TriggerBase trigger = style._visualTriggers[i]; // Set things up to handle Setter values for (int j = 0; j < trigger.PropertyValues.Count; j++) { PropertyValue propertyValue = trigger.PropertyValues[j]; // Check for trigger rules that act on container if (propertyValue.ChildName != StyleHelper.SelfName) { throw new InvalidOperationException(SR.Get(SRID.StyleTriggersCannotTargetTheTemplate)); } TriggerCondition[] conditions = propertyValue.Conditions; for (int k = 0; k < conditions.Length; k++) { if (conditions[k].SourceName != StyleHelper.SelfName) { throw new InvalidOperationException(SR.Get(SRID.TriggerOnStyleNotAllowedToHaveSource, conditions[k].SourceName)); } } // Track properties on the container that are being driven by // the Style so that they can be invalidated during style changes StyleHelper.AddContainerDependent(propertyValue.Property, true /*fromVisualTrigger*/, ref this.ContainerDependents); StyleHelper.UpdateTables(ref propertyValue, ref ChildRecordFromChildIndex, ref TriggerSourceRecordFromChildIndex, ref ResourceDependents, ref _dataTriggerRecordFromBinding, null /*_childIndexFromChildID*/, ref _hasInstanceValues); } // Set things up to handle TriggerActions if (trigger.HasEnterActions || trigger.HasExitActions) { if (trigger is Trigger) { StyleHelper.AddPropertyTriggerWithAction(trigger, ((Trigger)trigger).Property, ref this.PropertyTriggersWithActions); } else if (trigger is MultiTrigger) { MultiTrigger multiTrigger = (MultiTrigger)trigger; for (int k = 0; k < multiTrigger.Conditions.Count; k++) { Condition triggerCondition = multiTrigger.Conditions[k]; StyleHelper.AddPropertyTriggerWithAction(trigger, triggerCondition.Property, ref this.PropertyTriggersWithActions); } } else if (trigger is DataTrigger) { StyleHelper.AddDataTriggerWithAction(trigger, ((DataTrigger)trigger).Binding, ref this.DataTriggersWithActions); } else if (trigger is MultiDataTrigger) { MultiDataTrigger multiDataTrigger = (MultiDataTrigger)trigger; for (int k = 0; k < multiDataTrigger.Conditions.Count; k++) { Condition dataCondition = multiDataTrigger.Conditions[k]; StyleHelper.AddDataTriggerWithAction(trigger, dataCondition.Binding, ref this.DataTriggersWithActions); } } else { throw new InvalidOperationException(SR.Get(SRID.UnsupportedTriggerInStyle, trigger.GetType().Name)); } } // Set things up to handle EventTrigger EventTrigger eventTrigger = trigger as EventTrigger; if (eventTrigger != null) { if (eventTrigger.SourceName != null && eventTrigger.SourceName.Length > 0) { throw new InvalidOperationException(SR.Get(SRID.EventTriggerOnStyleNotAllowedToHaveTarget, eventTrigger.SourceName)); } StyleHelper.ProcessEventTrigger(eventTrigger, null /*_childIndexFromChildID*/, ref _triggerActions, ref EventDependents, null /*_templateFactoryRoot*/, null, ref _eventHandlersStore, ref _hasLoadedChangeHandler); } } } }
/// <summary> /// Sets a value specifying whether trace is enabled for the specified trigger /// </summary> /// <param name="trigger"></param> /// <param name="value"></param> public static void SetTraceEnabled(TriggerBase trigger, bool value) { trigger.SetValue(TraceEnabledProperty, value); }
/// <summary> /// Gets a value indication whether trace is enabled for the specified trigger. /// </summary> /// <param name="trigger">The trigger.</param> /// <returns></returns> public static bool GetTraceEnabled(TriggerBase trigger) { return (bool)trigger.GetValue(TraceEnabledProperty); }
/// <summary> /// Sets the trigger name for the specified trigger. This will be used /// to identify the trigger in the debug output. /// </summary> /// <param name="trigger">The trigger.</param> /// <returns></returns> public static void SetTriggerName(TriggerBase trigger, string value) { trigger.SetValue(TriggerNameProperty, value); }
// Helper method shared between property trigger and data trigger. After // the trigger's old and new states are evaluated, look at them and see // if we should invoke the associated EnterActions or ExitActions. private static void InvokeEnterOrExitActions( TriggerBase triggerBase, bool oldState, bool newState, DependencyObject triggerContainer, Style style, FrameworkTemplate frameworkTemplate) { TriggerActionCollection actions; if( !oldState && newState ) { // False -> True transition. Execute EnterActions. actions = triggerBase.EnterActions; } else if( oldState && !newState ) { // True -> False transition. Execute ExitActions. actions = triggerBase.ExitActions; } else { actions = null; } InvokeActions( actions, triggerBase, triggerContainer, style, frameworkTemplate ); }
// This is expected to be called when a property value has changed and that // property is specified as a condition in a trigger. // We're given the trigger here, the property changed, and the before/after state. // Evaluate the Trigger, and see if we need to invoke any of the TriggerAction // objects associated with the given trigger. private static void InvokePropertyTriggerActions( TriggerBase triggerBase, DependencyObject triggerContainer, DependencyProperty changedProperty, DependencyPropertyChangedEventArgs changedArgs, int sourceChildIndex, Style style, FrameworkTemplate frameworkTemplate ) { bool oldState; bool newState; Trigger trigger = triggerBase as Trigger; if( trigger != null ) { EvaluateOldNewStates( trigger, triggerContainer, changedProperty, changedArgs, sourceChildIndex, style, frameworkTemplate, out oldState, out newState ); } else { Debug.Assert( triggerBase is MultiTrigger, "This method only handles Trigger and MultiTrigger. Other types should have been handled elsewhere." ); EvaluateOldNewStates( (MultiTrigger)triggerBase, triggerContainer, changedProperty, changedArgs, sourceChildIndex, style, frameworkTemplate, out oldState, out newState ); } InvokeEnterOrExitActions( triggerBase, oldState, newState, triggerContainer, style, frameworkTemplate ); }
// Called during Style/Template Seal when encountering a property trigger that // has associated TriggerActions. internal static void AddPropertyTriggerWithAction(TriggerBase triggerBase, DependencyProperty property, ref FrugalMap triggersWithActions) { object existing = triggersWithActions[property.GlobalIndex]; if( existing == DependencyProperty.UnsetValue ) { // No existing trigger, we put given trigger as entry. triggersWithActions[property.GlobalIndex] = triggerBase; } else { TriggerBase existingTriggerBase = existing as TriggerBase; if( existingTriggerBase != null ) { List<TriggerBase> newList = new List<TriggerBase>(); newList.Add(existingTriggerBase); newList.Add(triggerBase); triggersWithActions[property.GlobalIndex] = newList; } else { Debug.Assert( existing is List<TriggerBase>, "FrugalMap for holding List<TriggerBase> is holding an instance of unexpected type " + existing.GetType() ); List<TriggerBase> existingList = (List<TriggerBase>)existing; existingList.Add(triggerBase); } } // Note the order in which we processed this trigger. triggerBase.EstablishLayer(); }
// Called during Style/Template Seal when encountering a data trigger that // has associated TriggerActions. internal static void AddDataTriggerWithAction(TriggerBase triggerBase, BindingBase binding, ref HybridDictionary dataTriggersWithActions ) { if( dataTriggersWithActions == null ) { dataTriggersWithActions = new HybridDictionary(); } object existing = dataTriggersWithActions[binding]; if( existing == null ) { // No existing trigger, we put given trigger as entry. dataTriggersWithActions[binding] = triggerBase; } else { TriggerBase existingTriggerBase = existing as TriggerBase; if( existingTriggerBase != null ) { // Up-convert to list and replace. List<TriggerBase> newList = new List<TriggerBase>(); newList.Add(existingTriggerBase); newList.Add(triggerBase); dataTriggersWithActions[binding] = newList; } else { Debug.Assert( existing is List<TriggerBase>, "HybridDictionary for holding List<TriggerBase> is holding an instance of unexpected type " + existing.GetType() ); List<TriggerBase> existingList = (List<TriggerBase>)existing; existingList.Add(triggerBase); } } // Note the order in which we processed this trigger. triggerBase.EstablishLayer(); }
// Given a list of action collection, invoke all individual TriggerAction // in that collection using the rest of the information given. internal static void InvokeActions( TriggerBase triggerBase, DependencyObject triggerContainer, TriggerActionCollection actions, Style style, FrameworkTemplate frameworkTemplate) { for (int i = 0; i < actions.Count; i++) { TriggerAction action = actions[i]; Debug.Assert(!(action.ContainingTrigger is EventTrigger), "This trigger actions list used by this method are expected to contain only those actions under non-event triggers."); action.Invoke(triggerContainer as FrameworkElement, triggerContainer as FrameworkContentElement, style, frameworkTemplate, triggerBase.Layer); } }
// In the event that we can't do an immediate invoke of the collection // of actions, add this to the list of deferred actions that is stored // on the template object. Because each template can be applicable to // multiple objects, the storage of deferred actions is keyed by the // triggerContainer instance. private static void DeferActions( TriggerBase triggerBase, DependencyObject triggerContainer, TriggerActionCollection actions, Style style, FrameworkTemplate frameworkTemplate) { ConditionalWeakTable<DependencyObject, List<DeferredAction>> deferredActions; DeferredAction deferredAction; // struct deferredAction.TriggerBase = triggerBase; deferredAction.TriggerActionCollection = actions; if( frameworkTemplate != null ) { deferredActions = frameworkTemplate.DeferredActions; if( deferredActions == null ) { deferredActions = new ConditionalWeakTable<DependencyObject, List<DeferredAction>>(); frameworkTemplate.DeferredActions = deferredActions; } } else { // Nothing - deferring actions only happen for FrameworkTemplate // scenarios, so deferred actions is empty. deferredActions = null; } if( deferredActions != null ) { List<DeferredAction> actionList; if( !deferredActions.TryGetValue(triggerContainer, out actionList) ) { actionList = new List<DeferredAction>(); deferredActions.Add(/* key */triggerContainer,/* value */actionList); } actionList.Add(deferredAction); } }
// Called from InvokeEnterOrExitActions in response to a changed event, or // from ExecuteOnApplyEnterExitActionsLoop when Style/Template is initially // applied. // At this point we've decided that the given set of trigger action collections // should be run now. This method checks to see if that's actually possible // and either invokes immediately or saves enough information to invoke later. private static void InvokeActions( TriggerActionCollection actions, TriggerBase triggerBase, DependencyObject triggerContainer, Style style, FrameworkTemplate frameworkTemplate ) { if( actions != null ) { // See CanInvokeActionsNow for all the (known) reasons why we might not be able to // invoke immediately. if( CanInvokeActionsNow( triggerContainer, frameworkTemplate ) ) { InvokeActions( triggerBase, triggerContainer, actions, style, frameworkTemplate ); } else { DeferActions( triggerBase, triggerContainer, actions, style, frameworkTemplate ); } } }
//////////////////////////////////////////////////////////////////////// // ProcessOneTrigger // // Find the target element for this trigger, and set a listener for // the event into (pointing back to the trigger). internal static void ProcessOneTrigger( FrameworkElement triggersHost, TriggerBase triggerBase ) { // This code path is used in the element trigger case. We don't actually // need these guys to be usable cross-thread, so we don't really need // to freeze/seal these objects. The only one expected to cause problems // is a change to the RoutedEvent. At the same time we remove this // Seal(), the RoutedEvent setter will check to see if the handler has // already been created and refuse an update if so. // triggerBase.Seal(); EventTrigger eventTrigger = triggerBase as EventTrigger; if( eventTrigger != null ) { Debug.Assert( eventTrigger._routedEventHandler == null && eventTrigger._source == null); // PERF: Cache this result if it turns out we're doing a lot of lookups on the same name. eventTrigger._source = FrameworkElement.FindNamedFrameworkElement( triggersHost, eventTrigger.SourceName ); // Create a statefull event delegate (which keeps a ref to the FE). EventTriggerSourceListener listener = new EventTriggerSourceListener( eventTrigger, triggersHost ); // Store the RoutedEventHandler & target for use in DisconnectOneTrigger eventTrigger._routedEventHandler = new RoutedEventHandler(listener.Handler); eventTrigger._source.AddHandler( eventTrigger.RoutedEvent, eventTrigger._routedEventHandler, false /* HandledEventsToo */ ); } else { throw new InvalidOperationException(SR.Get(SRID.TriggersSupportsEventTriggersOnly)); } }
public TriggerTraceStoryboard(TriggerBase triggerBase, TriggerTraceStoryboardType storyboardType) { TriggerBase = triggerBase; StoryboardType = storyboardType; }
//////////////////////////////////////////////////////////////////////// // // DisconnectOneTrigger // // In ProcessOneTrigger, we connect an event trigger to the element // which it targets. Here, we remove the event listener to clean up. internal static void DisconnectOneTrigger( FrameworkElement triggersHost, TriggerBase triggerBase ) { EventTrigger eventTrigger = triggerBase as EventTrigger; if( eventTrigger != null ) { eventTrigger._source.RemoveHandler( eventTrigger.RoutedEvent, eventTrigger._routedEventHandler); eventTrigger._routedEventHandler = null; } else { throw new InvalidOperationException(SR.Get(SRID.TriggersSupportsEventTriggersOnly)); } }
/// <summary> /// Gets the trigger name for the specified trigger. This will be used /// to identify the trigger in the debug output. /// </summary> /// <param name="trigger">The trigger.</param> /// <returns></returns> public static string GetTriggerName(TriggerBase trigger) { return (string)trigger.GetValue(TriggerNameProperty); }
// Token: 0x060008DF RID: 2271 RVA: 0x0001CD9C File Offset: 0x0001AF9C private void ProcessVisualTriggers(Style style) { if (style == null) { return; } this.ProcessVisualTriggers(style._basedOn); if (style._visualTriggers != null) { int count = style._visualTriggers.Count; for (int i = 0; i < count; i++) { TriggerBase triggerBase = style._visualTriggers[i]; for (int j = 0; j < triggerBase.PropertyValues.Count; j++) { PropertyValue propertyValue = triggerBase.PropertyValues[j]; if (propertyValue.ChildName != "~Self") { throw new InvalidOperationException(SR.Get("StyleTriggersCannotTargetTheTemplate")); } TriggerCondition[] conditions = propertyValue.Conditions; for (int k = 0; k < conditions.Length; k++) { if (conditions[k].SourceName != "~Self") { throw new InvalidOperationException(SR.Get("TriggerOnStyleNotAllowedToHaveSource", new object[] { conditions[k].SourceName })); } } StyleHelper.AddContainerDependent(propertyValue.Property, true, ref this.ContainerDependents); StyleHelper.UpdateTables(ref propertyValue, ref this.ChildRecordFromChildIndex, ref this.TriggerSourceRecordFromChildIndex, ref this.ResourceDependents, ref this._dataTriggerRecordFromBinding, null, ref this._hasInstanceValues); } if (triggerBase.HasEnterActions || triggerBase.HasExitActions) { if (triggerBase is Trigger) { StyleHelper.AddPropertyTriggerWithAction(triggerBase, ((Trigger)triggerBase).Property, ref this.PropertyTriggersWithActions); } else if (triggerBase is MultiTrigger) { MultiTrigger multiTrigger = (MultiTrigger)triggerBase; for (int l = 0; l < multiTrigger.Conditions.Count; l++) { Condition condition = multiTrigger.Conditions[l]; StyleHelper.AddPropertyTriggerWithAction(triggerBase, condition.Property, ref this.PropertyTriggersWithActions); } } else if (triggerBase is DataTrigger) { StyleHelper.AddDataTriggerWithAction(triggerBase, ((DataTrigger)triggerBase).Binding, ref this.DataTriggersWithActions); } else { if (!(triggerBase is MultiDataTrigger)) { throw new InvalidOperationException(SR.Get("UnsupportedTriggerInStyle", new object[] { triggerBase.GetType().Name })); } MultiDataTrigger multiDataTrigger = (MultiDataTrigger)triggerBase; for (int m = 0; m < multiDataTrigger.Conditions.Count; m++) { Condition condition2 = multiDataTrigger.Conditions[m]; StyleHelper.AddDataTriggerWithAction(triggerBase, condition2.Binding, ref this.DataTriggersWithActions); } } } EventTrigger eventTrigger = triggerBase as EventTrigger; if (eventTrigger != null) { if (eventTrigger.SourceName != null && eventTrigger.SourceName.Length > 0) { throw new InvalidOperationException(SR.Get("EventTriggerOnStyleNotAllowedToHaveTarget", new object[] { eventTrigger.SourceName })); } StyleHelper.ProcessEventTrigger(eventTrigger, null, ref this._triggerActions, ref this.EventDependents, null, null, ref this._eventHandlersStore, ref this._hasLoadedChangeHandler); } } } }
// Used by ExecuteOnApplyEnterExitActionsLoop to determine whether the // particular trigger is dependent on any child nodes, by checking for // a SourceName string in the trigger. // We only check the two property trigger types here, data triggers // do not support being dependent on child nodes. private static bool NoSourceNameInTrigger( TriggerBase triggerBase ) { Trigger trigger = triggerBase as Trigger; if( trigger != null ) { if( trigger.SourceName == null ) { return true; } else { return false; } } else { MultiTrigger multiTrigger = triggerBase as MultiTrigger; if( multiTrigger != null ) { for( int i = 0; i < multiTrigger.Conditions.Count; i++ ) { if( multiTrigger.Conditions[i].SourceName != null ) { return false; } } // Ran through all the conditions - not a single SourceName was found. return true; } } // DataTrigger and MultiDataTrigger doesn't allow SourceName - so it's true that they have no SourceName. return true; }